Javascript 获取未发送 Cookie 标头 (CORS)

我正在尝试在 javascript 获取 CORS 请求中将 Cookie 发送到 PHP 脚本。请求从 https://sub1.example.com 开始并包含以下选项:

let response = await fetch('https://sub2.example.com/target.php', {
    method: "POST",
    headers: headers,
    body: formData,
    mode: 'cors',
    credentials: 'include',
    cache: 'no-store'
});

相应的 PHP 脚本设置以下标头:

header('Access-Control-Allow-Origin: https://www.example.com');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization, X-Request-With, Set-Cookie, Cookie, Bearer');

但是 Cookie 标头不会随请求一起发送。我也试过:

let headers = new Headers();
headers.set('Cookie', document.cookie);

那也没有效果。我在这里到底做错了什么?

我检查了开发工具中的网络选项卡。 PHP 脚本中的 $_COOKIE 也是空的。绝对没有错误。我还可以看到 Cookie 标头是在任何非 CORS fetch 请求中发送的。

编辑:这是其中一个 Cookie 的设置:

Name: PHPSESSID
Path: /
Secure: true
SameSite: none

我无法共享域,因为它不是公开的。但是 Cookie 域与请求标头中的 Origin 具有相同的值(减去 https://)。

编辑 2:更改了获取 URL 以使发生的事情更清楚。

stack overflow Javascript fetch is not sending Cookie Header (CORS)
原文答案
author avatar

接受的答案

问题

请注意,取决于

  • cookie 的 Path 属性的值,
  • cookie 的 Domain 属性的有效值,
  • cookie 的 Secure 属性的值,
  • cookie 的 SameSite attribute 的有效值,
  • 请求的发出和目的地来源,

cookie 可能会或可能不会附加到请求。与您的案例特别相关的是 Domain 属性;查看 MDN's page on the topic

Domain 属性指定哪些主机可以接收 cookie。如果未指定,则该属性默认为设置 cookie 的同一主机 excluding subdomains 。如果指定了 Domain is ,则始终包含子域。因此,指定 Domain 比省略它的限制要小。但是,当子域需要共享有关用户的信息时,它会很有帮助。

您在源 https://sub1.example.com 上按如下方式设置 cookie:

Set-Cookie: PHPSESSID=whatever; Path=/; SameSite=None; Secure

因此,该 cookie 将附加到目标来源为 https://sub1.example.com 的(有凭据的)请求,而没有其他请求。

解决方案

如果您希望将您的 cookie 发送到其域是 example.com 子域的所有安全源,则需要将其 Domain 显式设置为 example.com


关于使用 fetch 发送 cookie

Fetch standard 指定 forbidden header names 的列表; Cookie 就是其中之一。您不能在使用 Cookie 发送的请求上设置名为 fetch 的标头;标准只是 forbids it 。如果要将现有 cookie 附加到跨域请求,请使用在 'include' value for the credentials parameter 选项中传递的 fetch


答案:

作者头像

Cookie 通常不应该附加到 CORS 模式下的预检请求。你可能想看看这个。

注意:无论此设置如何,浏览器都不应在预检请求中发送凭据。有关更多信息,请参阅:CORS > 带有凭据的请求。

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

作者头像

为了让浏览器保存并使用使用 fetch 启动的 cookie,需要满足以下条件:

  1. 客户端使用 credentials: 'include' 异步初始化一个获取请求。见 [here][1] for more details.
  2. To do CORS, server response header must contain Access-Control-Allow-Origin explicitly set to a domain, could be different from the server domain. For example, in a Single-Page-App architecture, your frontend site is temporarily hosted at localhost:3000 and your backend server hosted at localhost:8000, then the header should be Access-Control-Allow-Origin: http://localhost:3000. See [here][2] and [here][3].
  3. To allow client to process cookies, which is obviously a sensitive resource, server response header must further contain Access-Control-Allow-Credentials: true. See [here][4]. Note that this enforces a non-wildcard setting for Access-Control-Allow-Origin. See [here][6] - that's why in point 2 above, it has to be explicitly set to something like http://localhost:3000 rather than *
  4. When server sets the cookie, it has to include SameSite=None; Secure; HttpOnly. So overall something like Set-Cookie: session_id=12345; SameSite=None; Secure; HttpOnly. SameSite seems to be a relatively [new requirement][5] in latest browsers, and must be used with Secure together when SameSite is set to None.
  5. With regard to HttpOnly, I haven't found relevant materials, but in my experiment, omitting it caused the browser to ignore the Set-Cookie header.
  6. Further requests to the backend server also must have credentials: 'include' set.

Source: https://stackoverflow.com/a/67001424/368691