Skip to content

Commit

Permalink
SameSite cookies: Consider redirect chain for same-site requests
Browse files Browse the repository at this point in the history
The cookie spec is being amended in
httpwg/http-extensions#1348
to consider the redirect chain when computing whether a request is
considered same-site.

This aligns with the new specification by considering a request cross-
site if any URL in the redirect chain was cross-site from the current
request URL.

Bug: 830101
Change-Id: I060026647ccea2a97267e865c8292ac64915e87b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2605504
Commit-Queue: Lily Chen <chlily@chromium.org>
Reviewed-by: Maksim Orlovich <morlovich@chromium.org>
Reviewed-by: Min Qin <qinmin@chromium.org>
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#860890}
GitOrigin-RevId: 306b8fba167a809c5389a58d65bee438ca3bd15d
  • Loading branch information
chlily1 authored and copybara-github committed Mar 8, 2021
1 parent 6f5b1cf commit 7663a61
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@
// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to same-host fetches are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to same-host fetches are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to same-host fetches are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.CROSS_SITE, "Cross-site redirecting to same-host fetches are cross-site");

// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to subdomain fetches are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to subdomain fetches are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to subdomain fetches are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.CROSS_SITE, "Cross-site redirecting to subdomain fetches are cross-site");

// Redirect from {same-host,subdomain,cross-site} to cross-site:
create_test(SECURE_CROSS_SITE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_CROSS_SITE_ORIGIN), SameSiteStatus.CROSS_SITE, "Same-host redirecting to cross-site fetches are cross-site");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@
// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to same-host top-level form GETs are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to same-host top-level form GETs are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to same-host top-level form GETs are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.LAX, "Cross-site redirecting to same-host top-level form GETs are laxly same-site");

// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to subdomain top-level form GETs are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to subdomain top-level form GETs are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to subdomain top-level form GETs are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.LAX, "Cross-site redirecting to subdomain top-level form GETs are laxly same-site");

// Redirect from {same-host,subdomain,cross-site} to cross-site:
create_test(SECURE_CROSS_SITE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_CROSS_SITE_ORIGIN), SameSiteStatus.LAX, "Same-host redirecting to cross-site top-level form GETs are laxly same-site");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@
// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to same-host top-level form POSTs are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to same-host top-level form POSTs are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to same-host top-level form POSTs are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.CROSS_SITE, "Cross-site redirecting to same-host top-level form POSTs are cross-site");

// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to subdomain top-level form POSTs are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to subdomain top-level form POSTs are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to subdomain top-level form POSTs are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.CROSS_SITE, "Cross-site redirecting to subdomain top-level form POSTs are cross-site");

// Redirect from {same-host,subdomain,cross-site} to cross-site:
create_test(SECURE_CROSS_SITE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_CROSS_SITE_ORIGIN), SameSiteStatus.CROSS_SITE, "Same-host redirecting to cross-site top-level form POSTs are cross-site");
Expand Down
4 changes: 2 additions & 2 deletions blink/web_tests/external/wpt/cookies/samesite/img.https.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@
// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to same-host images are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to same-host images are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to same-host images are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.CROSS_SITE, "Cross-site redirecting to same-host images are cross-site");

// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to subdomain images are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to subdomain images are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to subdomain images are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.CROSS_SITE, "Cross-site redirecting to subdomain images are cross-site");

// Redirect from {same-host,subdomain,cross-site} to cross-site:
create_test(SECURE_CROSS_SITE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_CROSS_SITE_ORIGIN), SameSiteStatus.CROSS_SITE, "Same-host redirecting to cross-site images are cross-site");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@
// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to same-host images are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to same-host images are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to same-host images are strictly same-site");
create_test(SECURE_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_ORIGIN), SameSiteStatus.CROSS_SITE, "Cross-site redirecting to same-host images are cross-site");

// Redirect from {same-host,subdomain,cross-site} to same-host:
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Same-host redirecting to subdomain images are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_SUBDOMAIN_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Subdomain redirecting to subdomain images are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.STRICT, "Cross-site redirecting to subdomain images are strictly same-site");
create_test(SECURE_SUBDOMAIN_ORIGIN, redirectTo(SECURE_CROSS_SITE_ORIGIN, SECURE_SUBDOMAIN_ORIGIN), SameSiteStatus.CROSS_SITE, "Cross-site redirecting to subdomain images are cross-site");

// Redirect from {same-host,subdomain,cross-site} to cross-site:
create_test(SECURE_CROSS_SITE_ORIGIN, redirectTo(SECURE_ORIGIN, SECURE_CROSS_SITE_ORIGIN), SameSiteStatus.CROSS_SITE, "Same-host redirecting to cross-site images are cross-site");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Tests that fetch exposes cookies according to SameSite rules.
Request to https://setcookies.a.test/, type: Document
Request to https://subdomain.a.test/, type: Document
Request to https://a.test/, type: Document
Cookies after same-site navigation:
StrictCookie=1; LaxCookie=1; NoneCookie=1; UnspecifiedCookie=1
Request to https://b.test/, type: Document
Request to https://a.test/, type: Document
Cookies after cross-site navigation:
LaxCookie=1; NoneCookie=1; UnspecifiedCookie=1
Request to https://subdomain.a.test/, type: Document
Request to https://a.test/, type: Document
Cookies for same-site iframe:
StrictCookie=1; LaxCookie=1; NoneCookie=1; UnspecifiedCookie=1
Request to https://b.test/, type: Document
Request to https://a.test/, type: Document
Cookies for cross-site iframe:
NoneCookie=1
Request to https://subdomain.a.test/, type: Document
Request to https://redirect.a.test/, type: Document
Request to https://a.test/, type: Document
Cookies for same-site initiated same-site redirect:
StrictCookie=1; LaxCookie=1; NoneCookie=1; UnspecifiedCookie=1
Request to https://subdomain.a.test/, type: Document
Request to https://redirect.b.test/, type: Document
Request to https://a.test/, type: Document
Cookies for same-site initiated cross-site redirect:
LaxCookie=1; NoneCookie=1; UnspecifiedCookie=1
Request to https://b.test/, type: Document
Request to https://redirect.a.test/, type: Document
Request to https://a.test/, type: Document
Cookies for cross-site initiated same-site redirect:
LaxCookie=1; NoneCookie=1; UnspecifiedCookie=1
Request to https://b.test/, type: Document
Request to https://redirect.b.test/, type: Document
Request to https://a.test/, type: Document
Cookies for cross-site initiated cross-site redirect:
LaxCookie=1; NoneCookie=1; UnspecifiedCookie=1
Request to https://subdomain.a.test/, type: Document
Request to https://redirect.a.test/, type: Document
Request to https://a.test/, type: Document
Cookies for same-site embedded same-site redirect:
StrictCookie=1; LaxCookie=1; NoneCookie=1; UnspecifiedCookie=1
Request to https://subdomain.a.test/, type: Document
Request to https://redirect.b.test/, type: Document
Request to https://a.test/, type: Document
Cookies for same-site embedded cross-site redirect:
NoneCookie=1
Request to https://b.test/, type: Document
Request to https://redirect.a.test/, type: Document
Request to https://a.test/, type: Document
Cookies for cross-site embedded same-site redirect:
NoneCookie=1
Request to https://b.test/, type: Document
Request to https://redirect.b.test/, type: Document
Request to https://a.test/, type: Document
Cookies for cross-site embedded cross-site redirect:
NoneCookie=1

Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
(async function(testRunner) {
const {page, session, dp} = await testRunner.startBlank(
`Tests that fetch exposes cookies according to SameSite rules.`);

const FetchHelper = await testRunner.loadScript('resources/fetch-test.js');
const helper = new FetchHelper(testRunner, testRunner.browserP());
await helper.enable();

helper.onceRequest(/setcookies.a.test/).fulfill({
responseCode: 200,
responseHeaders: [
{name: 'Set-Cookie', value: 'StrictCookie=1; Secure; SameSite=Strict; Domain=a.test'},
{name: 'Set-Cookie', value: 'LaxCookie=1; Secure; SameSite=Lax; Domain=a.test'},
{name: 'Set-Cookie', value: 'NoneCookie=1; Secure; SameSite=None; Domain=a.test'},
{name: 'Set-Cookie', value: 'UnspecifiedCookie=1; Secure; Domain=a.test'}
],
body: btoa("<html></html>")
});

await dp.Page.enable();
await session.navigate('https://setcookies.a.test/');

// URL whose cookies are dumped in the following tests.
const cookieUrl = 'https://a.test/';

// Set up redirect to a.test from any URL containing 'redirect'.
helper.onRequest(/redirect/).fulfill({
responseCode: 302,
responseHeaders: [{name: 'Location', value: cookieUrl}]
});

// Returns a string containing a script to append an iframe to the DOM.
function appendIframeScript(url) {
// This may run before or after the page is fully loaded, so account for
// both cases to avoid flakiness.
return `
function appendIframe() {
var frame = document.createElement('iframe');
frame.src = '${url}';
document.body.appendChild(frame);
}
window.onload = appendIframe;
if (document.readyState === 'complete')
appendIframe();`
}

// Navigates to `fromUrl`, then navigates to a.test and dumps cookies that
// were sent.
async function navigateAndDumpCookies(fromUrl, description) {
// Navigate to the starting location.
helper.onceRequest(new RegExp(fromUrl)).fulfill({
responseCode: 200,
body: btoa("<html></html>")
});
await dp.Page.navigate({url: fromUrl});
// Navigate to a.test.
session.evaluate(`location.href = '${cookieUrl}'`);
const request = await helper.onceRequest(cookieUrl).matched();
testRunner.log(`Cookies after ${description}:`);
testRunner.log(request.request.headers['Cookie']);
dp.Fetch.fulfillRequest({requestId: request.requestId, responseCode: 200});
}

// Navigates to `mainUrl`, then loads a.test in an iframe and dumps cookies
// that were sent.
async function loadIframeAndDumpCookies(mainUrl, description) {
// Navigate to the main page URL.
helper.onceRequest(new RegExp(mainUrl)).fulfill({
responseCode: 200,
body: btoa("<html></html>")
});
await dp.Page.navigate({url: mainUrl});
// Load iframe with a.test.
session.evaluate(appendIframeScript(cookieUrl));
const request = await helper.onceRequest(cookieUrl).matched();
testRunner.log(`Cookies for ${description}:`);
testRunner.log(request.request.headers['Cookie']);
dp.Fetch.fulfillRequest({requestId: request.requestId, responseCode: 200});
}

// Navigates to `fromUrl`, then navigates to `redirectUrl`, which then
// redirects to a.test and dumps cookies that were sent.
// `redirectUrl` must match the pattern /redirect/.
async function redirectAndDumpCookies(fromUrl, redirectUrl, description) {
helper.onceRequest(new RegExp(fromUrl)).fulfill({
responseCode: 200,
body: btoa("<html></html>")
});
// Navigate to the starting location.
await dp.Page.navigate({url: fromUrl});
// Navigate to `redirectUrl` which then redirects to a.test.
session.evaluate(`location.href = '${redirectUrl}'`);
const request = await helper.onceRequest(cookieUrl).matched();
testRunner.log(`Cookies for ${description}:`);
testRunner.log(request.request.headers['Cookie']);
dp.Fetch.fulfillRequest({requestId: request.requestId, responseCode: 200});
}

// Navigates to `mainUrl`, then loads `redirectUrl` in an iframe. The iframe
// then redirects to a.test and dumps cookies that were sent.
// `redirectUrl` must match the pattern /redirect/.
async function redirectInIframeAndDumpCookies(mainUrl, redirectUrl, description) {
helper.onceRequest(new RegExp(mainUrl)).fulfill({
responseCode: 200,
body: btoa("<html></html>")
});
// Navigate to the main page URL.
await dp.Page.navigate({url: mainUrl});
// Load an iframe with `redirectUrl` which then redirects to a.test.
session.evaluate(appendIframeScript(redirectUrl));
const request = await helper.onceRequest(cookieUrl).matched();
testRunner.log(`Cookies for ${description}:`);
testRunner.log(request.request.headers['Cookie']);
dp.Fetch.fulfillRequest({requestId: request.requestId, responseCode: 200});
}

await navigateAndDumpCookies('https://subdomain.a.test/', 'same-site navigation');
await navigateAndDumpCookies('https://b.test/', 'cross-site navigation');
await loadIframeAndDumpCookies('https://subdomain.a.test/', 'same-site iframe');
await loadIframeAndDumpCookies('https://b.test/', 'cross-site iframe');
await redirectAndDumpCookies('https://subdomain.a.test/', 'https://redirect.a.test/', 'same-site initiated same-site redirect');
await redirectAndDumpCookies('https://subdomain.a.test/', 'https://redirect.b.test/', 'same-site initiated cross-site redirect');
await redirectAndDumpCookies('https://b.test/', 'https://redirect.a.test/', 'cross-site initiated same-site redirect');
await redirectAndDumpCookies('https://b.test/', 'https://redirect.b.test/', 'cross-site initiated cross-site redirect');
await redirectInIframeAndDumpCookies('https://subdomain.a.test/', 'https://redirect.a.test/', 'same-site embedded same-site redirect');
await redirectInIframeAndDumpCookies('https://subdomain.a.test/', 'https://redirect.b.test/', 'same-site embedded cross-site redirect');
await redirectInIframeAndDumpCookies('https://b.test/', 'https://redirect.a.test/', 'cross-site embedded same-site redirect');
await redirectInIframeAndDumpCookies('https://b.test/', 'https://redirect.b.test/', 'cross-site embedded cross-site redirect');

testRunner.completeTest();
})

0 comments on commit 7663a61

Please sign in to comment.