- Edited
I found a routing issue in CodeIgniter 4 and have volunteered a fix for it. However, I started thinking today that this might not be entirely secure.
CI4 autorouting starts with the Router::autoRoute function which receives the path portion of a url. E.g., if you request https://www.example.com/subdir/nested-directory/long/path/stuff?blah+blah+blah
then CI4, failing to find any matching route, will call the autoRoute function with a $uri
of subdir/nested-directory/long/path/stuff
.
That function uses explode to split the $uri into $segments along the slashes and then calls (a very poorly named) function, Router::validateRequest which currently looks like this:
protected function validateRequest(array $segments): array
{
$segments = array_filter($segments, function ($segment) {
return ($segment || ($segment === '0'));
});
$segments = array_values($segments);
$c = count($segments);
$directoryOverride = isset($this->directory);
// Loop through our segments and return as soon as a controller
// is found or when such a directory doesn't exist
while ($c-- > 0)
{
$segmentConvert = ucfirst($this->translateURIDashes === true ? str_replace('-', '_', $segments[0]) : $segments[0]);
$test = APPPATH . 'Controllers/' . $this->directory . $segmentConvert;
if (! is_file($test . '.php') && $directoryOverride === false && is_dir($test))
{
$this->setDirectory($segmentConvert, true);
array_shift($segments);
continue;
}
return $segments;
}
// This means that all segments were actually directories
return $segments;
}
This function should be called something like findController or something. What it does is it strips off each segment, applying ucfirst and optionally mapping dashes to underscores to make a PSR-4 compliant path segment. It iterates through the $segments array until it either a) finds matching controller file or b) the segments no longer match directory names.
This function is taking user input directly from the user-supplied uri request and probes the controller directory looking for a matching controller. We must therefor carefully construct it to prevent mischief. Malicious users should not be able to construct uris which probe for sensitive files or execute arbitrary PHP files on the server.
If anyone could tell me how to construct a custom HTTPS request (telnet? ssh? curl?) where I can send some mischief, I'd appreciate it. For example, I tried this url but the double period (parent directory) segment was evaluated at some prior stage, either by firefox or apache, and the double period path segment doesn't make its way to the validateRequest function: https://www.cidev.com/../subdir/nested-directory
. I'd also like to be able to construct uris containing a backspace or delete characters or perhaps multibyte UTF8 codes. I tried using telnet to port 443 and pasted this:
GET /subdir/nested-directory HTTP/1.1 Host:www.example.com
but got a 400 response:
Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
Instead use the HTTPS scheme to access this URL, please.
The apache log file:
127.0.0.1 - - [19/Feb/2021:16:39:45 -0800] "GET / HTTP/1.0" 400 0 "-" "-"
I tried curl, too, but the parent-directory double period gets evaluated prior to the request getting sent:
curl -vk https://www.example.com/subdir/../nested-directory
For that last request, my apache log just shows:
127.0.0.1 - - [19/Feb/2021:16:37:15 -0800] "GET /nested-directory HTTP/1.1" 404 3146 "-" "curl/7.68.0"
I'd also like to know what kind of uri segments I should avoid, especially as this code will be scanning the file system. The code as written takes care to avoid empty string segments, and the setDirectory function removes any periods from any segment. Seems to me we should probably watch out for any reserved characters (i.e., chars not permitted in filenames). Should any such characters arrive in a segment, the code should probably stop scanning the file system and instead assume the segment was intended as input or parameter to be supplied to the controller that handles the request.
Any thoughts or advice would be much appreciated.