跨站点 cookie 的问题:如何将 cookie 从后端设置到前端

Posted

技术标签:

【中文标题】跨站点 cookie 的问题:如何将 cookie 从后端设置到前端【英文标题】:issue with cross-site cookies: how to set cookie from backend to frontend 【发布时间】:2020-11-10 14:23:07 【问题描述】:

我目前正在开发我的第一个 web 应用程序,前端使用 React,后端使用 FastAPI

我正在尝试与 Chrome 一起测试它——看看前端是否对后端进行了正确的 API 调用,并显示结果。我一直在使用 cookie 时遇到问题,我需要帮助。提前为这篇长文道歉——过去几天我浏览了很多资源,现在我不确定什么是相关的,什么不是。

localhost:8080 上的前端 http://127.0.0.1:8000 上的后端 使用以下FastAPI 后端代码正确设置 CORS(我相信):
app = FastAPI()

origins = [
    "http://localhost:8080"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

情况:前端向后端的http://127.0.0.1:8000/api/abc发出GET请求,后端设置了cookie。

/*===================== 尝试 1: 使用以下后端代码设置 cookie:

response.set_cookie(key="abcCookieKey", value="abcCookieValue")

并使用以下前端 JS 代码发出 GET 请求:

fetch('http://127.0.0.1:8000/api/abc', 
            method: 'GET',
            credentials: 'include',
        )

尝试 1 的结果: 在 Chrome 的 Console 标签上,我收到以下警告:

A cookie associated with a cross-site resource at http://127.0.0.1/ was set without the `SameSite` attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.

在网络选项卡上,我在检查 set-cookie 响应标头时收到以下消息:

This Set-Cookie was blocked because it has the "SameSite=Lax" attribute but came from a cross-site response which was not the response to a top-level navigation.

====================*/

...所以我做了一些研究,然后想出了

/*===================== 尝试 2: 使用以下后端代码设置 cookie:

response.set_cookie(key="abcCookieKey", value="abcCookieValue", samesite="none", secure=True)

并使用相同的前端 JS 代码发出 GET 请求。

尝试 2 的结果: 在 Chrome 的 Console 选项卡上,我收到与尝试 1 完全相同的警告,即使响应标头具有 set-cookieSamesite=none; Secure。此外,标题有以下警告

This Set-Cookie was blocked because it had the "Secure" attribute but was not received over a secure connection.

====================*/

..所以我尝试使用https 并提出:

/*===================== 尝试 3: 一切都与尝试 #2 相同,除了在我的 JS 获取代码中,我使用 fetch('https://127.0.0.1:8000/api/abc ... 然后我在使用uvicorn 运行的后端收到以下警告:WARNING: Invalid HTTP request received.

====================*/

问题:

    尝试#2 是否遗漏了什么?肯定有一种简单的方法来设置从后端到前端的 cookie,而不用担心 https? 如果我别无选择,只能使用https,如何在本地运行可以使用https 访问的后端服务器?我所做的研究使它看起来像是一个复杂/耗时的过程。 (但是,公平地说,我对 web-dev/all things network 的理解非常有限)。

【问题讨论】:

你解决了吗? 简短的回答是否定的,我没有解决它。我刚结束使用 Safari 来解决它,然后在部署后检查它是否可以在 Chrome 上运行。 你是怎么解决沙山的? 请发布答案@ShashanSooriyahetti,因为您可以看到我们很多人都想知道。 @Marisha 我已经添加了答案,因为你们要求随时问 anthing 【参考方案1】:

您可以通过转到“chrome://flags”并禁用“没有 SameSite 的 Cookie 必须是安全的”来完全禁用此功能。但是,这将对所有网站禁用它,因此当您不进行开发时,它的安全性会降低。

【讨论】:

这不起作用,我仍然收到“安全”错误【参考方案2】:

我会尝试给出这个概念。

首先请知道我使用的是从SailsJS 开发的后端和从AngularJS 开发的前端以及连接到使用Angular9 开发的后端的应用程序。

我正在为前端(CMS)使用仅限 http 的 cookie,以授予向已登录用户添加内容的权限。身份验证成功后,将为他们设置仅限 HTTP 的 cookie。

请注意,http cookie 有一个棘手的部分,并且后端和前端都提供不同的 URL,就像在呈现的场景中一样。

积分:

    因此,在开发过程中,您必须将后端和前端托管在同一 IP 下。 前任。我的后端:192.168.8.160:1337,前端:192.168.8.160:81。 不同的端口相同的ip。

    这不是投入生产时的场景,您可以拥有任何域:)

    您必须在后端允许 CORS 并让您的前端 ip:port 在接受的来源下。

    实施,你必须确定你的环境,在我的情况下,


if (sails.config.environment === 'development')
  res.setHeader('Set-Cookie',[`token=$token;  Path=/;HttpOnly; maxAge=86400000;SameSite=false;`]);
 else 
  res.setHeader('Set-Cookie',[`token=$token;  Path=/;HttpOnly; maxAge=86400000;SameSite=None;Secure=true;`]);



请注意,在上面的开发环境代码中,您需要SameSite=false,因此您需要具有相同的ip,因为我们不能拥有SameSite=None,因为它需要Secure=true,然后需要HTTPS。在开发模式下实现会很头疼。

就是这样,伙计们。如果你做对了,你就可以做到这一点。

【讨论】:

非常感谢...这个答案。节省了我的大量时间。我使用 Django + React(JWT Auth.)。当我在后端设置 Httponly cookie 但未在前端 api 请求中设置时。 我一整天都在尝试解决完全相同的问题。这个答案为我做了。我仍然不明白 samesite false 和 same samesite none 之间有什么区别。我以为我他们是完全相同的东西。无论如何,现在就可以了 如果您正在使用 create react app 并想使用 HTTPS,只需将 HTTPS=true 添加到 package.json 中的启动脚本: scripts: "start": "HTTPS=true react-scripts start " @Rem 不错,angular还支持带有ng s --ssl的HTTPS @hainabaraka,您应该立即将其标记为已接受的答案,这是一个真正出色的解释【参考方案3】:

删除通配符,因为allow_credentials=True 不允许使用通配符:

app.add_middleware(
  CORSMiddleware,
  allow_origins=['http://localhost:8080'],
  allow_credentials=True,
  allow_methods=["GET", "POST", "OPTIONS"], /* include additional methods as per the application demand */
  allow_headers=["Content-Type","Set-Cookie"], /* include additional headers as per the application demand */
)

在设置 cookie 时将 samesite 设置为 none(现代浏览器需要它):

/* `secure=True` is optional and used for secure https connections */
response.set_cookie(key='token_name', value='token_value', httponly=True, secure=True, samesite='none')

如果客户端使用 Safari,请禁用 Preferences 中的 Prevent cros-site tracking。就是这样!

【讨论】:

以上是关于跨站点 cookie 的问题:如何将 cookie 从后端设置到前端的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Boot 中设置同站点 cookie 标志?

Set-cookie 不适用于 Dot net Core 3.1 中的跨站点请求/响应和 React 设置同站点 cookie 和/或 CORS 问题

跨子域共享 ASP.NET cookie

跨站点请求伪造(CSRF)

未设置 Django CSRF cookie:使用 Ajax 跨站点

PHP 跨站点通用脚本(写入Cookie数据)