1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
From: Nicolas Grekas <nicolas.grekas@gmail.com>
Date: Tue, 22 Oct 2024 10:31:42 +0200
Subject: [HttpFoundation] Reject URIs that contain invalid characters
Origin: backport, https://github.com/symfony/symfony/commit/5a9b08e5740af795854b1b639b7d45b9cbfe8819
Bug: https://github.com/symfony/symfony/security/advisories/GHSA-mrqx-rp3w-jpjp
Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2024-50345
---
src/Symfony/Component/HttpFoundation/Request.php | 18 +++++++++++++
.../Component/HttpFoundation/Tests/RequestTest.php | 30 ++++++++++++++++++++--
2 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php
index 28cebad..acad3c9 100644
--- a/src/Symfony/Component/HttpFoundation/Request.php
+++ b/src/Symfony/Component/HttpFoundation/Request.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\HttpFoundation;
+use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException;
use Symfony\Component\HttpFoundation\Exception\JsonException;
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
@@ -330,6 +331,8 @@ class Request
* @param string|resource|null $content The raw body data
*
* @return static
+ *
+ * @throws BadRequestException When the URI is invalid
*/
public static function create(string $uri, string $method = 'GET', array $parameters = [], array $cookies = [], array $files = [], array $server = [], $content = null)
{
@@ -353,6 +356,21 @@ class Request
$server['REQUEST_METHOD'] = strtoupper($method);
$components = parse_url($uri);
+
+ if (false === $components) {
+ throw new BadRequestException('Invalid URI.');
+ }
+
+ if (false !== ($i = strpos($uri, '\\')) && $i < strcspn($uri, '?#')) {
+ throw new BadRequestException('Invalid URI: A URI cannot contain a backslash.');
+ }
+ if (\strlen($uri) !== strcspn($uri, "\r\n\t")) {
+ throw new BadRequestException('Invalid URI: A URI cannot contain CR/LF/TAB characters.');
+ }
+ if ('' !== $uri && (\ord($uri[0]) <= 32 || \ord($uri[-1]) <= 32)) {
+ throw new BadRequestException('Invalid URI: A URI must not start nor end with ASCII control characters or spaces.');
+ }
+
if (isset($components['host'])) {
$server['SERVER_NAME'] = $components['host'];
$server['HTTP_HOST'] = $components['host'];
diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
index e536080..993d95c 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
@@ -13,6 +13,7 @@ namespace Symfony\Component\HttpFoundation\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
+use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException;
use Symfony\Component\HttpFoundation\Exception\JsonException;
use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException;
@@ -286,9 +287,34 @@ class RequestTest extends TestCase
$this->assertTrue($request->isSecure());
// Fragment should not be included in the URI
- $request = Request::create('http://test.com/foo#bar');
- $request->server->set('REQUEST_URI', 'http://test.com/foo#bar');
+ $request = Request::create('http://test.com/foo#bar\\baz');
+ $request->server->set('REQUEST_URI', 'http://test.com/foo#bar\\baz');
$this->assertEquals('http://test.com/foo', $request->getUri());
+
+ $request = Request::create('http://test.com/foo?bar=f\\o');
+ $this->assertEquals('http://test.com/foo?bar=f%5Co', $request->getUri());
+ $this->assertEquals('/foo', $request->getPathInfo());
+ $this->assertEquals('bar=f%5Co', $request->getQueryString());
+ }
+
+ /**
+ * @testWith ["http://foo.com\\bar"]
+ * ["\\\\foo.com/bar"]
+ * ["a\rb"]
+ * ["a\nb"]
+ * ["a\tb"]
+ * ["\u0000foo"]
+ * ["foo\u0000"]
+ * [" foo"]
+ * ["foo "]
+ * [":"]
+ */
+ public function testCreateWithBadRequestUri(string $uri)
+ {
+ $this->expectException(BadRequestException::class);
+ $this->expectExceptionMessage('Invalid URI');
+
+ Request::create($uri);
}
/**
|