Express + React:CSRF Cookie 在生产中未定义,在本地工作
Posted
技术标签:
【中文标题】Express + React:CSRF Cookie 在生产中未定义,在本地工作【英文标题】:Express + React: CSRF Cookie is undefined in production, works locally 【发布时间】:2020-04-03 03:34:04 【问题描述】:我将我的 express API 托管在 Heroku 上,并将我的 客户端托管在 Netlify 上。当我在本地尝试我的注册路线时,我的 cookie 被定义并且该路线有效。但是,当它在生产中时,cookie 总是返回 undefined 并且我的 API 超时。
请注意,cookie 正在从后端成功发送。我可以在开发工具中查看它。此外,cookies,get() 返回一个空对象。
我正在使用 Js-cookie。
我在 Gatsby 中使用 js-cookie。我正在使用 CSURF 来表达 cookie。
后端:
//CSURF Config
app.use(csurf( cookie: true ));
//Route that generates CSRF Cookie
app.get("/getToken", (req, res) =>
res.cookie("XSRF-TOKEN", req.csrfToken());
res.end();
);
前端:
我包含了整个注册功能。请注意,这是两个端点调用,一个用于检索 cookie,另一个用于创建用户记录。
userSignUp = async (email, password, resetForm) =>
console.log("THis is a test of the emergency..")
await fetch(process.env.API + "getToken",
mode: "cors", // no-cors, cors, *include
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "include", // include, *include, omit
headers:
"content-type": "application/json",
,
method: "GET",
)
const token = Cookies.get("XSRF-TOKEN")
alert(Cookies.get("XSRF-TOKEN"))
const data = await fetch(process.env.API + "signUp",
body: JSON.stringify( email: email, password: password ),
mode: "cors", // no-cors, cors, *include
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "include", // include, *include, omit
headers:
"content-type": "application/json",
"csrf-token": token,
,
method: "POST",
).catch(error => this.setState( isError: true ))
if (data.ok)
console.log(data.ok)
data.json().then(content =>
console.log(content)
this.props.changeAuth(content.authStatus)
this.props.setCategories(content.user.categories)
this.props.getEvents(content.user.events)
resetForm()
)
else
this.setState(
isError: true,
)
【问题讨论】:
你的网页网址是什么,你的服务器网址是什么? 它们是不同的......一个是heroku随机url,另一个是netlify url注意它在本地主机端口3000(服务器)和本地主机端口8000(客户端)上工作。而且cookies是由服务器设置的。我可以在 chrome 开发工具中看到它们。 【参考方案1】:如果前端域和服务器域不同,cookie 将不起作用。
您可以set up a proxy through Netlify将所有请求重定向到前端域到后端域的路径(例如/api/
)。
要设置代理,您可以在发布目录中创建一个_redirects
文件(例如public
),配置如下:
/api/* https://<server-url>:<server-port>/:splat 200
最后,将所有 HTTP 请求发送到该前端路径(例如https://<front-end-url>/api/users
)而不是后端 URL,以确保 cookie 正常工作。
【讨论】:
我可以在我的开发控制台中看到 cookie,并且它们设置正确。 我猜它仍然会被设置,但cookies.get()
只会尝试从同一个域中获取 cookie。试试我的解决方案,看看它是否有效。
我会尽快尝试。谢谢。【参考方案2】:
...当它在生产中时,cookie 总是返回 undefined...
一个可能的原因可能是您在生产中使用 HTTPS(应该是这种情况)并且浏览器忽略了 CSRF cookie,因为它没有设置为安全 cookie。要解决此问题,请在生产中使用安全 cookie,在开发中使用非安全 cookie。
附言 要使第一个 cookie 安全,请替换此代码
app.use(csurf( cookie: true ));
这样:
app.use(csurf(
cookie:
httpOnly: true,
secure: !devModeFlag
));
httpOnly
设置可确保客户端上的 JS 无法触及此 cookie,这有助于提高安全性。布尔值 devModeFlag
变量应在开发中设置为 true,在生产中设置为 false。
要使第二个 cookie 安全,请替换此代码
res.cookie("XSRF-TOKEN", req.csrfToken());
这样:
res.cookie("XSRF-TOKEN", req.csrfToken(), secure: !devModeFlag );
【讨论】:
我尝试了这些更改,但无法让它们正常工作。更有趣的是,cookie 正在发送过来,我可以在开发工具中看到它们。当我执行 cookies.get() 时,它返回一个空对象。我的想法是,要么 Netlify 以一种奇怪的方式处理 cookie,要么 js-cookie 包或我使用它的方式有问题。 另一个问题是您在客户端使用credentials: "include"
,而不是set Access-Control-Allow-Credentials 标头。这个 MDN 页面说“both 服务器(使用 Access-Control-Allow-Credentials 标头)和客户端(通过设置 XHR、Fetch 或 Ajax 请求的凭据模式)必须表明它们'正在选择加入凭据'。我假设客户端 JS 是从 Netlify 而不是从 Heroku 服务器下载的。以上是关于Express + React:CSRF Cookie 在生产中未定义,在本地工作的主要内容,如果未能解决你的问题,请参考以下文章
使用 AngularJs 发布请求时未设置 CSRF Cookie - Django 后端