Skip to content

Commit e3ff079

Browse files
Release 7.4.4 (#3023)
1 parent 74a8602 commit e3ff079

File tree

3 files changed

+63
-12
lines changed

3 files changed

+63
-12
lines changed

Diff for: CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version.
44

5+
## 7.4.4 - 2022-06-09
6+
7+
* Fix failure to strip Authorization header on HTTP downgrade
8+
* Fix failure to strip the Cookie header on change in host or HTTP downgrade
9+
510
## 7.4.3 - 2022-05-25
611

712
* Fix cross-domain cookie leakage

Diff for: src/RedirectMiddleware.php

+34-7
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ static function (ResponseInterface $response) use ($uri, $statusCode) {
142142
}
143143

144144
/**
145-
* Check for too many redirects
145+
* Check for too many redirects.
146146
*
147147
* @throws TooManyRedirectsException Too many redirects.
148148
*/
@@ -178,7 +178,7 @@ public function modifyRequest(RequestInterface $request, array $options, Respons
178178
$modify['body'] = '';
179179
}
180180

181-
$uri = $this->redirectUri($request, $response, $protocols);
181+
$uri = self::redirectUri($request, $response, $protocols);
182182
if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
183183
$idnOptions = ($options['idn_conversion'] === true) ? \IDNA_DEFAULT : $options['idn_conversion'];
184184
$uri = Utils::idnUriConvert($uri, $idnOptions);
@@ -198,19 +198,46 @@ public function modifyRequest(RequestInterface $request, array $options, Respons
198198
$modify['remove_headers'][] = 'Referer';
199199
}
200200

201-
// Remove Authorization header if host is different.
202-
if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
201+
// Remove Authorization and Cookie headers if required.
202+
if (self::shouldStripSensitiveHeaders($request->getUri(), $modify['uri'])) {
203203
$modify['remove_headers'][] = 'Authorization';
204+
$modify['remove_headers'][] = 'Cookie';
204205
}
205206

206207
return Psr7\Utils::modifyRequest($request, $modify);
207208
}
208209

209210
/**
210-
* Set the appropriate URL on the request based on the location header
211+
* Determine if we should strip sensitive headers from the request.
212+
*
213+
* We return true if either of the following conditions are true:
214+
*
215+
* 1. the host is different;
216+
* 2. the scheme has changed, and now is non-https.
211217
*/
212-
private function redirectUri(RequestInterface $request, ResponseInterface $response, array $protocols): UriInterface
213-
{
218+
private static function shouldStripSensitiveHeaders(
219+
UriInterface $originalUri,
220+
UriInterface $modifiedUri
221+
): bool {
222+
if (\strcasecmp($originalUri->getHost(), $modifiedUri->getHost()) !== 0) {
223+
return true;
224+
}
225+
226+
if ($originalUri->getScheme() !== $modifiedUri->getScheme() && 'https' !== $modifiedUri->getScheme()) {
227+
return true;
228+
}
229+
230+
return false;
231+
}
232+
233+
/**
234+
* Set the appropriate URL on the request based on the location header.
235+
*/
236+
private static function redirectUri(
237+
RequestInterface $request,
238+
ResponseInterface $response,
239+
array $protocols
240+
): UriInterface {
214241
$location = Psr7\UriResolver::resolve(
215242
$request->getUri(),
216243
new Psr7\Uri($response->getHeaderLine('Location'))

Diff for: tests/RedirectMiddlewareTest.php

+24-5
Original file line numberDiff line numberDiff line change
@@ -272,18 +272,37 @@ public function testInvokesOnRedirectForRedirects()
272272
self::assertTrue($call);
273273
}
274274

275-
public function testRemoveAuthorizationHeaderOnRedirect()
275+
public function crossOriginRedirectProvider()
276+
{
277+
return [
278+
['http://example.com?a=b', 'http://test.com/', false],
279+
['https://example.com?a=b', 'https://test.com/', false],
280+
['http://example.com?a=b', 'https://test.com/', false],
281+
['https://example.com?a=b', 'http://test.com/', false],
282+
['http://example.com?a=b', 'http://example.com/', true],
283+
['https://example.com?a=b', 'https://example.com/', true],
284+
['http://example.com?a=b', 'https://example.com/', true],
285+
['https://example.com?a=b', 'http://example.com/', false],
286+
];
287+
}
288+
289+
/**
290+
* @dataProvider crossOriginRedirectProvider
291+
*/
292+
public function testHeadersTreatmentOnRedirect($originalUri, $targetUri, $shouldBePresent)
276293
{
277294
$mock = new MockHandler([
278-
new Response(302, ['Location' => 'http://test.com']),
279-
static function (RequestInterface $request) {
280-
self::assertFalse($request->hasHeader('Authorization'));
295+
new Response(302, ['Location' => $targetUri]),
296+
static function (RequestInterface $request) use ($shouldBePresent) {
297+
self::assertSame($shouldBePresent, $request->hasHeader('Authorization'));
298+
self::assertSame($shouldBePresent, $request->hasHeader('Cookie'));
299+
281300
return new Response(200);
282301
}
283302
]);
284303
$handler = HandlerStack::create($mock);
285304
$client = new Client(['handler' => $handler]);
286-
$client->get('http://example.com?a=b', ['auth' => ['testuser', 'testpass']]);
305+
$client->get($originalUri, ['auth' => ['testuser', 'testpass'], 'headers' => ['Cookie' => 'foo=bar']]);
287306
}
288307

289308
public function testNotRemoveAuthorizationHeaderOnRedirect()

0 commit comments

Comments
 (0)