diff --git a/system/Session/Handlers/Database/PostgreHandler.php b/system/Session/Handlers/Database/PostgreHandler.php index 1471d44d1860..37ab7e6dfdc1 100644 --- a/system/Session/Handlers/Database/PostgreHandler.php +++ b/system/Session/Handlers/Database/PostgreHandler.php @@ -59,7 +59,7 @@ protected function prepareData(string $data): string * @param int $max_lifetime Sessions that have not updated * for the last max_lifetime seconds will be removed. */ - public function gc($max_lifetime): false|int + public function gc(int $max_lifetime): false|int { $separator = '\''; $interval = implode($separator, ['', "{$max_lifetime} second", '']); diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index c4ce2b8222e7..6ddd8a3c0d9b 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -276,7 +276,7 @@ public function destroy($id): bool * * @return false|int Returns the number of deleted sessions on success, or false on failure. */ - public function gc($max_lifetime): false|int + public function gc(int $max_lifetime): false|int { return $this->db->table($this->table)->where( 'timestamp <', diff --git a/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php b/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php index 743508d7fe55..05612dd39bcb 100644 --- a/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php +++ b/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php @@ -18,7 +18,9 @@ use CodeIgniter\Test\DatabaseTestTrait; use CodeIgniter\Test\ReflectionHelper; use Config\Database as DatabaseConfig; +use stdClass; use Tests\Support\Database\Seeds\CITestSeeder; +use TypeError; /** * @internal @@ -122,4 +124,18 @@ public function testGC(): void $handler = $this->getInstance(); $this->assertSame(1, $handler->gc(3600)); } + + public function testGCRejectsNonInt(): void + { + $handler = $this->getInstance(); + + foreach (['malicious; DROP TABLE sessions; --', null, 1.5, [], new stdClass(), true] as $malicious) { + try { + $handler->gc($malicious); // @phpstan-ignore argument.type + $this->fail('TypeError expected for value: ' . gettype($malicious)); + } catch (TypeError) { + $this->addToAssertionCount(1); + } + } + } } diff --git a/user_guide_src/source/changelogs/v4.7.5.rst b/user_guide_src/source/changelogs/v4.7.5.rst index c4bb7900e07a..a7b672901ab6 100644 --- a/user_guide_src/source/changelogs/v4.7.5.rst +++ b/user_guide_src/source/changelogs/v4.7.5.rst @@ -31,6 +31,7 @@ Bugs Fixed ********** - **Logger:** Fixed a bug where interpolating a log message with array or non-stringable context values could raise PHP warnings or errors. +- **Session:** Added ``int`` type hint to ``DatabaseHandler::gc()`` and ``PostgreHandler::gc()`` to prevent SQL injection from non-integer ``$max_lifetime`` values. See the repo's `CHANGELOG.md `_