Skip to content

Commit

Permalink
[6.x] Fix cross-domain cookie leakage (#3017)
Browse files Browse the repository at this point in the history
Co-authored-by: Tim Düsterhus <209270+TimWolla@users.noreply.github.com>
  • Loading branch information
GrahamCampbell and TimWolla committed May 25, 2022
1 parent e8ed4db commit f092dd7
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 113 deletions.
7 changes: 3 additions & 4 deletions .gitattributes
@@ -1,8 +1,7 @@
.editorconfig export-ignore
.gitattributes export-ignore
.editorconfig export-ignore
.gitattributes export-ignore
/.github/ export-ignore
.gitignore export-ignore
/.travis.yml export-ignore
.gitignore export-ignore
/build/ export-ignore
/docs/ export-ignore
/Makefile export-ignore
Expand Down
70 changes: 70 additions & 0 deletions .github/workflows/ci.yml
@@ -0,0 +1,70 @@
name: CI

on:
push:
branches:
- master
pull_request:

jobs:
build-lowest:
name: Build lowest
runs-on: ubuntu-latest

steps:
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '5.5'
coverage: none
extensions: mbstring, intl

- name: Set up Node
uses: actions/setup-node@v1
with:
node-version: '14.x'

- name: Setup Problem Matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

- name: Checkout code
uses: actions/checkout@v2

- name: Download dependencies
run: composer update --no-interaction --no-progress --prefer-stable --prefer-lowest

- name: Run tests
run: make test

build:
name: Build
runs-on: ubuntu-latest
strategy:
max-parallel: 10
matrix:
php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4']

steps:
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
extensions: mbstring, intl

- name: Set up Node
uses: actions/setup-node@v1
with:
node-version: '14.x'

- name: Setup Problem Matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

- name: Checkout code
uses: actions/checkout@v2

- name: Download dependencies
run: composer update --no-interaction --no-progress

- name: Run tests
run: make test
36 changes: 0 additions & 36 deletions .github/workflows/static.yml

This file was deleted.

56 changes: 0 additions & 56 deletions .travis.yml

This file was deleted.

4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,9 @@
# Change Log

## 6.5.6 - 2022-05-25

* Fix cross-domain cookie leakage

## 6.5.5 - 2020-06-16

* Unpin version constraint for `symfony/polyfill-intl-idn` [#2678](https://github.com/guzzle/guzzle/pull/2678)
Expand Down
10 changes: 9 additions & 1 deletion LICENSE
@@ -1,4 +1,12 @@
Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
The MIT License (MIT)

Copyright (c) 2011 Michael Dowling <mtdowling@gmail.com>
Copyright (c) 2012 Jeremy Lindblom <jeremeamia@gmail.com>
Copyright (c) 2014 Graham Campbell <hello@gjcampbell.co.uk>
Copyright (c) 2015 Márk Sági-Kazár <mark.sagikazar@gmail.com>
Copyright (c) 2015 Tobias Schultze <webmaster@tubo-world.de>
Copyright (c) 2016 Tobias Nyholm <tobias.nyholm@gmail.com>
Copyright (c) 2016 George Mponos <gmponos@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
23 changes: 13 additions & 10 deletions README.md
Expand Up @@ -2,7 +2,7 @@ Guzzle, PHP HTTP client
=======================

[![Latest Version](https://img.shields.io/github/release/guzzle/guzzle.svg?style=flat-square)](https://github.com/guzzle/guzzle/releases)
[![Build Status](https://img.shields.io/travis/guzzle/guzzle.svg?style=flat-square)](https://travis-ci.org/guzzle/guzzle)
[![Build Status](https://img.shields.io/github/workflow/status/guzzle/guzzle/CI?label=ci%20build&style=flat-square)](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI)
[![Total Downloads](https://img.shields.io/packagist/dt/guzzlehttp/guzzle.svg?style=flat-square)](https://packagist.org/packages/guzzlehttp/guzzle)

Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
Expand Down Expand Up @@ -74,17 +74,20 @@ composer update

## Version Guidance

| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
|---------|------------|---------------------|--------------|---------------------|---------------------|-------|-------------|
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >= 5.3.3 |
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >= 5.4 |
| 5.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >= 5.4 |
| 6.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >= 5.5 |
| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
|---------|----------------|---------------------|--------------|---------------------|---------------------|-------|--------------|
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 |
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 |
| 5.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 |
| 6.x | Security fixes | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 |
| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.2 |

[guzzle-3-repo]: https://github.com/guzzle/guzzle3
[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x
[guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3
[guzzle-6-repo]: https://github.com/guzzle/guzzle
[guzzle-6-repo]: https://github.com/guzzle/guzzle/tree/6.5
[guzzle-7-repo]: https://github.com/guzzle/guzzle
[guzzle-3-docs]: http://guzzle3.readthedocs.org
[guzzle-5-docs]: http://guzzle.readthedocs.org/en/5.3/
[guzzle-6-docs]: http://guzzle.readthedocs.org/en/latest/
[guzzle-5-docs]: http://docs.guzzlephp.org/en/5.3/
[guzzle-6-docs]: http://docs.guzzlephp.org/en/6.5/
[guzzle-7-docs]: http://docs.guzzlephp.org/en/latest/
30 changes: 30 additions & 0 deletions composer.json
Expand Up @@ -14,10 +14,40 @@
"homepage": "http://guzzlephp.org/",
"license": "MIT",
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
},
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Jeremy Lindblom",
"email": "jeremeamia@gmail.com",
"homepage": "https://github.com/jeremeamia"
},
{
"name": "George Mponos",
"email": "gmponos@gmail.com",
"homepage": "https://github.com/gmponos"
},
{
"name": "Tobias Nyholm",
"email": "tobias.nyholm@gmail.com",
"homepage": "https://github.com/Nyholm"
},
{
"name": "Márk Sági-Kazár",
"email": "mark.sagikazar@gmail.com",
"homepage": "https://github.com/sagikazarmark"
},
{
"name": "Tobias Schultze",
"email": "webmaster@tubo-world.de",
"homepage": "https://github.com/Tobion"
}
],
"require": {
Expand Down
5 changes: 5 additions & 0 deletions src/Cookie/CookieJar.php
Expand Up @@ -240,6 +240,11 @@ public function extractCookies(
if (0 !== strpos($sc->getPath(), '/')) {
$sc->setPath($this->getCookiePathFromRequest($request));
}
if (!$sc->matchesDomain($request->getUri()->getHost())) {
continue;
}
// Note: At this point `$sc->getDomain()` being a public suffix should
// be rejected, but we don't want to pull in the full PSL dependency.
$this->setCookie($sc);
}
}
Expand Down
11 changes: 9 additions & 2 deletions src/Cookie/SetCookie.php
Expand Up @@ -333,12 +333,19 @@ public function matchesPath($requestPath)
*/
public function matchesDomain($domain)
{
$cookieDomain = $this->getDomain();
if (null === $cookieDomain) {
return true;
}

// Remove the leading '.' as per spec in RFC 6265.
// http://tools.ietf.org/html/rfc6265#section-5.2.3
$cookieDomain = ltrim($this->getDomain(), '.');
$cookieDomain = ltrim(strtolower($cookieDomain), '.');

$domain = strtolower($domain);

// Domain not set or exact match.
if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
if ('' === $cookieDomain || $domain === $cookieDomain) {
return true;
}

Expand Down
37 changes: 33 additions & 4 deletions tests/Cookie/CookieJarTest.php
Expand Up @@ -385,9 +385,6 @@ public function getCookiePathsDataProvider()
['/foo', '/'],
['/foo/bar', '/foo'],
['/foo/bar/', '/foo/bar'],
['foo', '/'],
['foo/bar', '/'],
['foo/bar/', '/'],
];
}

Expand All @@ -406,13 +403,45 @@ public function testCookiePathWithEmptySetCookiePath($uriPath, $cookiePath)
"bar=foo; expires={$this->futureExpirationDate()}; domain=www.example.com; path=foobar;"
)
;
$request = (new Request('GET', $uriPath))->withHeader('Host', 'www.example.com');
$request = (new Request('GET', "https://www.example.com{$uriPath}"));
$this->jar->extractCookies($request, $response);

self::assertSame($cookiePath, $this->jar->toArray()[0]['Path']);
self::assertSame($cookiePath, $this->jar->toArray()[1]['Path']);
}

public function getDomainMatchesProvider()
{
return [
['www.example.com', 'www.example.com', true],
['www.example.com', 'www.EXAMPLE.com', true],
['www.example.com', 'www.example.net', false],
['www.example.com', 'ftp.example.com', false],
['www.example.com', 'example.com', true],
['www.example.com', 'EXAMPLE.com', true],
['fra.de.example.com', 'EXAMPLE.com', true],
['www.EXAMPLE.com', 'www.example.com', true],
['www.EXAMPLE.com', 'www.example.COM', true],
];
}

/**
* @dataProvider getDomainMatchesProvider
*/
public function testIgnoresCookiesForMismatchingDomains($requestHost, $domainAttribute, $matches)
{
$response = (new Response(200))
->withAddedHeader(
'Set-Cookie',
"foo=bar; expires={$this->futureExpirationDate()}; domain={$domainAttribute}; path=/;"
)
;
$request = (new Request('GET', "https://{$requestHost}/"));
$this->jar->extractCookies($request, $response);

self::assertCount($matches ? 1 : 0, $this->jar->toArray());
}

private function futureExpirationDate()
{
return (new DateTimeImmutable)->add(new DateInterval('P1D'))->format(DateTime::COOKIE);
Expand Down

0 comments on commit f092dd7

Please sign in to comment.