Skip to content

Commit 05409da

Browse files
committed
feature #61949 [HttpFoundation] Deprecate HTTP method override for methods GET, HEAD, CONNECT and TRACE (nicolas-grekas)
This PR was merged into the 7.4 branch. Discussion ---------- [HttpFoundation] Deprecate HTTP method override for methods GET, HEAD, CONNECT and TRACE | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | no | New feature? | no | Deprecations? | yes | Issues | - | License | MIT Using HTTP method overriding (or HTTP verb tunneling) for those methods is dangerous and unneeded: the technique has been created to submit forms using HTTP verbs that browsers don't support. GET is not one of them, so that the trick shouldn't be applied to it. HEAD, CONNECT, TRACE are also NOT something browser should do - there's no point for a Symfony app to be the recipient of such requests (well, HEAD maybe, but since it should mimic a GET, it has to be in the list). This should make Symfony safer by default, since using a POST to tunnel a GET might lead to security-sensitive stuff. Commits ------- 167edf1 [HttpFoundation] Deprecate HTTP method override for methods GET, HEAD, CONNECT and TRACE
2 parents 1a5b5e5 + 167edf1 commit 05409da

File tree

9 files changed

+36
-18
lines changed

9 files changed

+36
-18
lines changed

UPGRADE-7.4.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ HttpFoundation
8282
* Add argument `$subtypeFallback` to `Request::getFormat()`
8383
* Deprecate using `Request::sendHeaders()` after headers have already been sent; use a `StreamedResponse` instead
8484
* Deprecate method `Request::get()`, use properties `->attributes`, `query` or `request` directly instead
85+
* Deprecate HTTP method override for methods GET, HEAD, CONNECT and TRACE; it will be ignored in Symfony 8.0
8586

8687
HttpKernel
8788
----------

src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ public function testOpeningDisallowedPaths($path, $isAllowed)
182182
$controller = new ProfilerController($urlGenerator, $profiler, $twig, [], null, __DIR__.'/../..');
183183

184184
try {
185-
$response = $controller->openAction(Request::create('/_wdt/open', Request::METHOD_GET, ['file' => $path]));
185+
$response = $controller->openAction(Request::create('/_wdt/open', 'GET', ['file' => $path]));
186186
$this->assertEquals(200, $response->getStatusCode());
187187
$this->assertTrue($isAllowed);
188188
} catch (NotFoundHttpException $e) {

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ CHANGELOG
1111
* Deprecate using `Request::sendHeaders()` after headers have already been sent; use a `StreamedResponse` instead
1212
* Deprecate method `Request::get()`, use properties `->attributes`, `query` or `request` directly instead
1313
* Make `Request::createFromGlobals()` parse the body of PUT, DELETE, PATCH and QUERY requests
14+
* Deprecate HTTP method override for methods GET, HEAD, CONNECT and TRACE; it will be ignored in Symfony 8.0
1415

1516
7.3
1617
---

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,10 @@ public function getMethod(): string
12441244

12451245
$method = strtoupper($method);
12461246

1247+
if (\in_array($method, ['GET', 'HEAD', 'CONNECT', 'TRACE'], true)) {
1248+
trigger_deprecation('symfony/http-foundation', '7.4', 'HTTP method override is deprecated for methods GET, HEAD, CONNECT and TRACE; it will be ignored in Symfony 8.0.', $method);
1249+
}
1250+
12471251
if (self::$allowedHttpMethodOverride && !\in_array($method, self::$allowedHttpMethodOverride, true)) {
12481252
return $this->method;
12491253
}

src/Symfony/Component/HttpFoundation/Tests/RequestTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,18 @@ public function testGetSetMethod()
10791079
$this->assertSame('POST', $request->getMethod(), '->getMethod() returns the request method if invalid type is defined in query');
10801080
}
10811081

1082+
#[IgnoreDeprecations]
1083+
#[Group('legacy')]
1084+
public function testUnsafeMethodOverride()
1085+
{
1086+
$request = new Request();
1087+
$request->setMethod('POST');
1088+
$request->headers->set('X-HTTP-METHOD-OVERRIDE', 'get');
1089+
1090+
$this->expectUserDeprecationMessage('Since symfony/http-foundation 7.4: HTTP method override is deprecated for methods GET, HEAD, CONNECT and TRACE; it will be ignored in Symfony 8.0.');
1091+
$this->assertSame('GET', $request->getMethod());
1092+
}
1093+
10821094
#[DataProvider('getClientIpsProvider')]
10831095
public function testGetClientIp($expected, $remoteAddr, $httpForwardedFor, $trustedProxies)
10841096
{

src/Symfony/Component/HttpKernel/HttpCache/AbstractSurrogate.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function needsParsing(Response $response): bool
7070

7171
public function handle(HttpCache $cache, string $uri, string $alt, bool $ignoreErrors): string
7272
{
73-
$subRequest = Request::create($uri, Request::METHOD_GET, [], $cache->getRequest()->cookies->all(), [], $cache->getRequest()->server->all());
73+
$subRequest = Request::create($uri, 'GET', [], $cache->getRequest()->cookies->all(), [], $cache->getRequest()->server->all());
7474

7575
try {
7676
$response = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true);

src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ public function testConfigKeyForQueryString()
937937
$argument = new ArgumentMetadata('filtered', QueryPayload::class, false, false, null, false, [
938938
MapQueryString::class => new MapQueryString(key: 'value'),
939939
]);
940-
$request = Request::create('/', Request::METHOD_GET, ['value' => ['page' => 1.0]]);
940+
$request = Request::create('/', 'GET', ['value' => ['page' => 1.0]]);
941941

942942
$kernel = $this->createMock(HttpKernelInterface::class);
943943
$arguments = $resolver->resolve($request, $argument);

src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractLoginFormAuthenticatorTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public static function provideSupportsData(): iterable
3434
{
3535
yield [
3636
'/login',
37-
Request::create('http://localhost/login', Request::METHOD_POST, [], [], [], [
37+
Request::create('http://localhost/login', 'POST', [], [], [], [
3838
'DOCUMENT_ROOT' => '/var/www/app/public',
3939
'PHP_SELF' => '/index.php',
4040
'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
@@ -44,7 +44,7 @@ public static function provideSupportsData(): iterable
4444
];
4545
yield [
4646
'/login',
47-
Request::create('http://localhost/somepath', Request::METHOD_POST, [], [], [], [
47+
Request::create('http://localhost/somepath', 'POST', [], [], [], [
4848
'DOCUMENT_ROOT' => '/var/www/app/public',
4949
'PHP_SELF' => '/index.php',
5050
'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
@@ -54,7 +54,7 @@ public static function provideSupportsData(): iterable
5454
];
5555
yield [
5656
'/folder/login',
57-
Request::create('http://localhost/folder/login', Request::METHOD_POST, [], [], [], [
57+
Request::create('http://localhost/folder/login', 'POST', [], [], [], [
5858
'DOCUMENT_ROOT' => '/var/www/app/public',
5959
'PHP_SELF' => '/folder/index.php',
6060
'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
@@ -64,7 +64,7 @@ public static function provideSupportsData(): iterable
6464
];
6565
yield [
6666
'/folder/login',
67-
Request::create('http://localhost/folder/somepath', Request::METHOD_POST, [], [], [], [
67+
Request::create('http://localhost/folder/somepath', 'POST', [], [], [], [
6868
'DOCUMENT_ROOT' => '/var/www/app/public',
6969
'PHP_SELF' => '/folder/index.php',
7070
'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
@@ -74,7 +74,7 @@ public static function provideSupportsData(): iterable
7474
];
7575
yield [
7676
'/index.php/login',
77-
Request::create('http://localhost/index.php/login', Request::METHOD_POST, [], [], [], [
77+
Request::create('http://localhost/index.php/login', 'POST', [], [], [], [
7878
'DOCUMENT_ROOT' => '/var/www/app/public',
7979
'PHP_SELF' => '/index.php',
8080
'SCRIPT_FILENAME' => '/var/www/app/public/index.php',
@@ -84,7 +84,7 @@ public static function provideSupportsData(): iterable
8484
];
8585
yield [
8686
'/index.php/login',
87-
Request::create('http://localhost/index.php/somepath', Request::METHOD_POST, [], [], [], [
87+
Request::create('http://localhost/index.php/somepath', 'POST', [], [], [], [
8888
'DOCUMENT_ROOT' => '/var/www/app/public',
8989
'PHP_SELF' => '/index.php',
9090
'SCRIPT_FILENAME' => '/var/www/app/public/index.php',

src/Symfony/Component/Security/Http/Tests/Authenticator/AccessToken/FormEncodedBodyAccessTokenAuthenticatorTest.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function testSupport()
4040
$this->setUpAuthenticator();
4141
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);
4242
$request->request->set('access_token', 'INVALID_ACCESS_TOKEN');
43-
$request->setMethod(Request::METHOD_POST);
43+
$request->setMethod('POST');
4444

4545
$this->assertNull($this->authenticator->supports($request));
4646
}
@@ -50,7 +50,7 @@ public function testSupportsWithCustomParameter()
5050
$this->setUpAuthenticator('protection-token');
5151
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);
5252
$request->request->set('protection-token', 'INVALID_ACCESS_TOKEN');
53-
$request->setMethod(Request::METHOD_POST);
53+
$request->setMethod('POST');
5454

5555
$this->assertNull($this->authenticator->supports($request));
5656
}
@@ -61,7 +61,7 @@ public function testAuthenticate()
6161
$this->setUpAuthenticator();
6262
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded'], 'access_token=VALID_ACCESS_TOKEN');
6363
$request->request->set('access_token', 'VALID_ACCESS_TOKEN');
64-
$request->setMethod(Request::METHOD_POST);
64+
$request->setMethod('POST');
6565

6666
$passport = $this->authenticator->authenticate($request);
6767
$this->assertInstanceOf(SelfValidatingPassport::class, $passport);
@@ -73,7 +73,7 @@ public function testAuthenticateWithCustomParameter()
7373
$this->setUpAuthenticator('protection-token');
7474
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);
7575
$request->request->set('protection-token', 'VALID_ACCESS_TOKEN');
76-
$request->setMethod(Request::METHOD_POST);
76+
$request->setMethod('POST');
7777

7878
$passport = $this->authenticator->authenticate($request);
7979
$this->assertInstanceOf(SelfValidatingPassport::class, $passport);
@@ -93,24 +93,24 @@ public function testAuthenticateInvalid(Request $request, string $errorMessage,
9393
public static function provideInvalidAuthenticateData(): iterable
9494
{
9595
$request = new Request();
96-
$request->setMethod(Request::METHOD_GET);
96+
$request->setMethod('GET');
9797
yield [$request, 'Invalid credentials.', BadCredentialsException::class];
9898

9999
$request = new Request();
100-
$request->setMethod(Request::METHOD_POST);
100+
$request->setMethod('POST');
101101
yield [$request, 'Invalid credentials.', BadCredentialsException::class];
102102

103103
$request = new Request([], [], [], [], [], ['HTTP_AUTHORIZATION' => 'Bearer VALID_ACCESS_TOKEN']);
104-
$request->setMethod(Request::METHOD_POST);
104+
$request->setMethod('POST');
105105
yield [$request, 'Invalid credentials.', BadCredentialsException::class];
106106

107107
$request = new Request();
108-
$request->setMethod(Request::METHOD_POST);
108+
$request->setMethod('POST');
109109
$request->request->set('foo', 'VALID_ACCESS_TOKEN');
110110
yield [$request, 'Invalid credentials.', BadCredentialsException::class];
111111

112112
$request = new Request([], [], [], [], [], ['CONTENT_TYPE' => 'application/x-www-form-urlencoded']);
113-
$request->setMethod(Request::METHOD_POST);
113+
$request->setMethod('POST');
114114
$request->request->set('access_token', 'INVALID_ACCESS_TOKEN');
115115
yield [$request, 'Invalid access token or invalid user.', BadCredentialsException::class];
116116
}

0 commit comments

Comments
 (0)