Search code examples
http-redirectcookiessamesite

SameSite=Strict cookies and cross-site requests with redirections


Cross-site requests do not include same-site cookies, but what happens if such a request leads to a redirection within the target site?

I tested this with the following Node.js express app running on https://site-a.com:

app.get("/a", function(req, res) {
  res.cookie("a", "b", {sameSite: "strict", secure: true, httpOnly: true});
  res.end();
})
.get("/b", function(req, res) {
  res.end(req.get("Cookie"));
})
.get("/c", function(req, res) {
  res.redirect("/b");
})
.get("/d", function(req, res) {
  res.send(`<!DOCTYPE html><html><body onload="location.href='/b'"></body></html>`);
});

and an HTML page https://site-b.com that contains cross-site hyperlinks to https://site-a.com/b, https://site-a.com/c and https://site-a.com/d.

I performed the following steps with Google Chrome (version 109.0.5414.75):

  1. Go to https://site-a.com/a in a browser window. This sets the same-site cookie.
  2. Open the HTML page at https://site-b.com.
  3. Clicking the /b link does not send the same-site cookie.
  4. Clicking the /c link does not send the same-site cookie, neither with the first request GET /c (which leads to an HTTP redirection) nor with the second request GET /b that results from the redirection.
  5. Clicking the /d link does not send the same-site cookie with the first request GET /d (which serves an HTML page), but does send it with the second request GET /b that results from the Javascript redirection in the HTML page.

I am surprised by the difference in behavior between steps 4 (HTTP redirection) and 5 (Javascript redirection).


Solution

  • The difference is explained by criterion 3 in the definition of same-site. A same-site cookie is sent in a request whose client has the same origin as its URL. In the given example, this means that the request's client must have origin https://site-a.com for the cookie to be sent.

    • The request's client of the HTTP-redirected request in step 4 is still https://site-b.com, because the request's client does not change during an HTTP-redirect fetch.
    • The request's client of the Javascript-redirected request in step 5 is https://site-a.com, because an HTML page from that origin has been loaded and the second request is a second scheme fetch, not an HTTP-redirect fetch.