Skip to content

Commit f7822a7

Browse files
security #cve-2022-24894 [HttpKernel] Remove private headers before storing responses with HttpCache (nicolas-grekas)
This PR was merged into the 4.4 branch.
2 parents 4e36db8 + 728a192 commit f7822a7

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

HttpCache/Store.php

+17-3
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,29 @@ class Store implements StoreInterface
2626
{
2727
protected $root;
2828
private $keyCache;
29-
private $locks;
29+
private $locks = [];
30+
private $options;
3031

3132
/**
33+
* Constructor.
34+
*
35+
* The available options are:
36+
*
37+
* * private_headers Set of response headers that should not be stored
38+
* when a response is cached. (default: Set-Cookie)
39+
*
3240
* @throws \RuntimeException
3341
*/
34-
public function __construct(string $root)
42+
public function __construct(string $root, array $options = [])
3543
{
3644
$this->root = $root;
3745
if (!file_exists($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) {
3846
throw new \RuntimeException(sprintf('Unable to create the store directory (%s).', $this->root));
3947
}
4048
$this->keyCache = new \SplObjectStorage();
41-
$this->locks = [];
49+
$this->options = array_merge([
50+
'private_headers' => ['Set-Cookie'],
51+
], $options);
4252
}
4353

4454
/**
@@ -215,6 +225,10 @@ public function write(Request $request, Response $response)
215225
$headers = $this->persistResponse($response);
216226
unset($headers['age']);
217227

228+
foreach ($this->options['private_headers'] as $h) {
229+
unset($headers[strtolower($h)]);
230+
}
231+
218232
array_unshift($entries, [$storedEnv, $headers]);
219233

220234
if (!$this->save($key, serialize($entries))) {

Tests/HttpCache/StoreTest.php

+13
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
namespace Symfony\Component\HttpKernel\Tests\HttpCache;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\HttpFoundation\Cookie;
1516
use Symfony\Component\HttpFoundation\Request;
1617
use Symfony\Component\HttpFoundation\Response;
18+
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
1719
use Symfony\Component\HttpKernel\HttpCache\Store;
1820

1921
class StoreTest extends TestCase
@@ -317,6 +319,17 @@ public function testPurgeHttpAndHttps()
317319
$this->assertEmpty($this->getStoreMetadata($requestHttps));
318320
}
319321

322+
public function testDoesNotStorePrivateHeaders()
323+
{
324+
$request = Request::create('https://example.com/foo');
325+
$response = new Response('foo');
326+
$response->headers->setCookie(Cookie::fromString('foo=bar'));
327+
328+
$this->store->write($request, $response);
329+
$this->assertArrayNotHasKey('set-cookie', $this->getStoreMetadata($request)[0][1]);
330+
$this->assertNotEmpty($response->headers->getCookies());
331+
}
332+
320333
protected function storeSimpleEntry($path = null, $headers = [])
321334
{
322335
if (null === $path) {

0 commit comments

Comments
 (0)