fix: add missing URI Security and Conig\App::$permittedURIChars

This commit is contained in:
kenjis 2024-03-15 14:23:30 +09:00
parent 7f0cab1e6c
commit 4d6b45b769
No known key found for this signature in database
GPG Key ID: BD254878922AF198
8 changed files with 159 additions and 0 deletions

View File

@ -59,6 +59,30 @@ class App extends BaseConfig
*/
public string $uriProtocol = 'REQUEST_URI';
/*
|--------------------------------------------------------------------------
| Allowed URL Characters
|--------------------------------------------------------------------------
|
| This lets you specify which characters are permitted within your URLs.
| When someone tries to submit a URL with disallowed characters they will
| get a warning message.
|
| As a security measure you are STRONGLY encouraged to restrict URLs to
| as few characters as possible.
|
| By default, only these are allowed: `a-z 0-9~%.:_-`
|
| Set an empty string to allow all characters -- but only if you are insane.
|
| The configured value is actually a regular expression character group
| and it will be used as: '/\A[<permittedURIChars>]+\z/iu'
|
| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
|
*/
public string $permittedURIChars = 'a-z 0-9~%.:_\-';
/**
* --------------------------------------------------------------------------
* Default Locale

View File

@ -0,0 +1,28 @@
<?php
/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <admin@codeigniter.com>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace CodeIgniter\HTTP\Exceptions;
use CodeIgniter\Exceptions\HTTPExceptionInterface;
use RuntimeException;
/**
* 400 Bad Request
*/
class BadRequestException extends RuntimeException implements HTTPExceptionInterface
{
/**
* HTTP status code for Bad Request
*
* @var int
*/
protected $code = 400; // @phpstan-ignore-line
}

View File

@ -13,6 +13,7 @@ namespace CodeIgniter\Router;
use Closure;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\Exceptions\BadRequestException;
use CodeIgniter\HTTP\Exceptions\RedirectException;
use CodeIgniter\HTTP\Request;
use CodeIgniter\HTTP\ResponseInterface;
@ -120,11 +121,23 @@ class Router implements RouterInterface
protected ?AutoRouterInterface $autoRouter = null;
/**
* Permitted URI chars
*
* The default value is `''` (do not check) for backward compatibility.
*/
protected string $permittedURIChars = '';
/**
* Stores a reference to the RouteCollection object.
*/
public function __construct(RouteCollectionInterface $routes, ?Request $request = null)
{
$config = config(App::class);
if (isset($config->permittedURIChars)) {
$this->permittedURIChars = $config->permittedURIChars;
}
$this->collection = $routes;
// These are only for auto-routing
@ -179,6 +192,8 @@ class Router implements RouterInterface
// Decode URL-encoded string
$uri = urldecode($uri);
$this->checkDisallowedChars($uri);
// Restart filterInfo
$this->filterInfo = null;
$this->filtersInfo = [];
@ -676,4 +691,20 @@ class Router implements RouterInterface
$this->matchedRouteOptions = $this->collection->getRoutesOptions($route);
}
/**
* Checks disallowed characters
*/
private function checkDisallowedChars(string $uri): void
{
foreach (explode('/', $uri) as $segment) {
if ($segment !== '' && $this->permittedURIChars !== ''
&& preg_match('/\A[' . $this->permittedURIChars . ']+\z/iu', $segment) !== 1
) {
throw new BadRequestException(
'The URI you submitted has disallowed characters: "' . $segment . '"'
);
}
}
}
}

View File

@ -13,10 +13,12 @@ namespace CodeIgniter\Router;
use CodeIgniter\Config\Services;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\HTTP\Exceptions\BadRequestException;
use CodeIgniter\HTTP\Exceptions\RedirectException;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\Router\Exceptions\RouterException;
use CodeIgniter\Test\CIUnitTestCase;
use Config\App;
use Config\Modules;
use Config\Routing;
use Tests\Support\Filters\Customfilter;
@ -87,6 +89,16 @@ final class RouterTest extends CIUnitTestCase
$router->handle('0');
}
public function testNotPermittedChars(): void
{
$router = new Router($this->collection, $this->request);
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('The URI you submitted has disallowed characters: "<a>"');
$router->handle('test/%3Ca%3E');
}
public function testURIMapsToController(): void
{
$router = new Router($this->collection, $this->request);
@ -783,6 +795,9 @@ final class RouterTest extends CIUnitTestCase
*/
public function testRegularExpressionWithUnicode(): void
{
$config = config(App::class);
$config->permittedURIChars = 'a-z 0-9~%.:_\-\x{0980}-\x{09ff}';
$this->collection->get('news/([a-z0-9\x{0980}-\x{09ff}-]+)', 'News::view/$1');
$router = new Router($this->collection, $this->request);
@ -802,6 +817,9 @@ final class RouterTest extends CIUnitTestCase
*/
public function testRegularExpressionPlaceholderWithUnicode(): void
{
$config = config(App::class);
$config->permittedURIChars = 'a-z 0-9~%.:_\-\x{0980}-\x{09ff}';
$this->collection->addPlaceholder('custom', '[a-z0-9\x{0980}-\x{09ff}-]+');
$this->collection->get('news/(:custom)', 'News::view/$1');

View File

@ -10,6 +10,15 @@ Release Date: Unreleased
:local:
:depth: 3
********
SECURITY
********
- **URI Security:** The feature to check if URIs do not contain not permitted
strings has been added. This check is equivalent to the URI Security found in
CodeIgniter 3. This is enabled by default, but upgraded users need to add
a setting to enable it. See :ref:`urls-uri-security` for details.
********
BREAKING
********

View File

@ -38,6 +38,7 @@ OWASP recommendations
CodeIgniter provisions
======================
- :ref:`urls-uri-security`
- :ref:`invalidchars` filter
- :doc:`../libraries/validation` library
- :doc:`HTTP library <../incoming/incomingrequest>` provides for :ref:`input field filtering <incomingrequest-filtering-input-data>` & content metadata

View File

@ -58,6 +58,39 @@ Route path /blog/news/2022/10 The URI path relative to the Bas
Query page=2
========== ==================================== =========================================
.. _urls-uri-security:
URI Security
============
.. versionadded:: 4.4.7
.. important::
Users upgrading from versions prior to v4.4.7 will need to add the following
to **app/Config/App.php** in order to use this feature::
public string $permittedURIChars = 'a-z 0-9~%.:_\-';
CodeIgniter is fairly restrictive regarding which characters it allows in your
URI strings (Route path) in order to help minimize the possibility that malicious
data can be passed to your application. URIs may only contain the following:
- Alpha-numeric text (latin characters only)
- Tilde: ``~``
- Percent sign: ``%``
- Period: ``.``
- Colon: ``:``
- Underscore: ``_``
- Dash: ``-``
- Space: `` ``
This setting can be changed by ``Config\App::$permittedURIChars``.
.. note::
This check is performed by the ``Router``. The Router takes the URL-encoded
value held by the ``SiteURI`` class, decodes it, and then checks that it
does not contain not permitted strings.
.. _urls-remove-index-php:
Removing the index.php file

View File

@ -16,6 +16,18 @@ Please refer to the upgrade instructions corresponding to your installation meth
Mandatory File Changes
**********************
URI Security
============
The feature to check if URIs do not contain not permitted strings has been added.
This check is equivalent to the URI Security found in CodeIgniter 3.
We recommend you enable this feature. Add the following to **app/Config/App.php**::
public string $permittedURIChars = 'a-z 0-9~%.:_\-';.
See :ref:`urls-uri-security` for details.
Error Files
===========
@ -66,6 +78,9 @@ and it is recommended that you merge the updated versions with your application:
Config
------
- app/Config/App.php
- The property ``$permittedURIChars`` was added. See :ref:`urls-uri-security`
for details.
- @TODO
All Changes