Skip to content

Commit

Permalink
security #cve-2022-24894 [HttpKernel] Remove private headers before s…
Browse files Browse the repository at this point in the history
…toring responses with HttpCache (nicolas-grekas)

This PR was merged into the 4.4 branch.
  • Loading branch information
nicolas-grekas committed Jan 24, 2023
2 parents 4e36db8 + 728a192 commit f7822a7
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 3 deletions.
20 changes: 17 additions & 3 deletions HttpCache/Store.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,29 @@ class Store implements StoreInterface
{
protected $root;
private $keyCache;
private $locks;
private $locks = [];
private $options;

/**
* Constructor.
*
* The available options are:
*
* * private_headers Set of response headers that should not be stored
* when a response is cached. (default: Set-Cookie)
*
* @throws \RuntimeException
*/
public function __construct(string $root)
public function __construct(string $root, array $options = [])
{
$this->root = $root;
if (!file_exists($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) {
throw new \RuntimeException(sprintf('Unable to create the store directory (%s).', $this->root));
}
$this->keyCache = new \SplObjectStorage();
$this->locks = [];
$this->options = array_merge([
'private_headers' => ['Set-Cookie'],
], $options);
}

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

foreach ($this->options['private_headers'] as $h) {
unset($headers[strtolower($h)]);
}

array_unshift($entries, [$storedEnv, $headers]);

if (!$this->save($key, serialize($entries))) {
Expand Down
13 changes: 13 additions & 0 deletions Tests/HttpCache/StoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
namespace Symfony\Component\HttpKernel\Tests\HttpCache;

use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
use Symfony\Component\HttpKernel\HttpCache\Store;

class StoreTest extends TestCase
Expand Down Expand Up @@ -317,6 +319,17 @@ public function testPurgeHttpAndHttps()
$this->assertEmpty($this->getStoreMetadata($requestHttps));
}

public function testDoesNotStorePrivateHeaders()
{
$request = Request::create('https://example.com/foo');
$response = new Response('foo');
$response->headers->setCookie(Cookie::fromString('foo=bar'));

$this->store->write($request, $response);
$this->assertArrayNotHasKey('set-cookie', $this->getStoreMetadata($request)[0][1]);
$this->assertNotEmpty($response->headers->getCookies());
}

protected function storeSimpleEntry($path = null, $headers = [])
{
if (null === $path) {
Expand Down

0 comments on commit f7822a7

Please sign in to comment.