Express + React:CSRF Coo​​kie 在生产中未定义,在本地工作

Posted

技术标签:

【中文标题】Express + React:CSRF Coo​​kie 在生产中未定义,在本地工作【英文标题】: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://&lt;front-end-url&gt;/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 Coo​​kie 在生产中未定义,在本地工作的主要内容,如果未能解决你的问题,请参考以下文章

使用 AngularJs 发布请求时未设置 CSRF Coo​​kie - Django 后端

Laravel 6 会话和 CSRF Coo​​kie 未设置——每次页面加载的会话数据库中的新条目

我必须在 React SPA 中使用 csrf 保护吗?

如何在 Express 中生成 CSRF 令牌?

实战:Express 模拟 CSRF 攻击

为啥 Express/Connect 会在每个请求上生成新的 CSRF 令牌?