JavaScript无法设置在XHR响应中接收到的http cookie。

7

我有一个基本的SPA(react)<->API(net core 2.2)设置,有2个环境:dev和prod(小项目)。 API端有一个认证机制,检查每个请求中是否包含JWT的httponlycookie。

在dev环境中,它工作得很好:allowCredentials()在API中设置,withCredentials = true在react应用程序中也是如此。两者运行在我的localhost的不同端口上。

但是在生产环境(独立的Heroku dynos)中,它就是不会设置httponlycookie:我可以使用我的凭据登录,响应头包含带有jwt的cookie,但我将进行的每个其他请求都不会在请求头中包含cookie头!

然后我会收到一个401 Unauthorized ...错误(这是合理的)。这令我抓狂,因为我花了几个小时尝试了所有可能的方法。

我的简单身份验证XHR(vanilla)调用:

var request = new XMLHttpRequest()
request.open('POST', apiAuthenticateUser, true)
request.setRequestHeader('Content-type', 'application/json')
request.withCredentials = true
request.send(postData)

我在 .net core api 中的 Startup.cs 配置:

public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
        IdentityModelEventSource.ShowPII = true;
    } else {
        app.UseHsts();
    }
    app.UseHttpsRedirection();

    app.UseCors(
        options => options.WithOrigins(
                "https://localhost:3000",
    "*productionEnvUrl*").AllowAnyMethod().AllowCredentials().AllowAnyHeader()
    );

    app.UseMvc(routes => {
        routes.MapRoute("MainRoute", "api/{controller}/{action}");
    });

    app.UseAuthentication();
}

这就是我如何在API控制器操作响应中设置含有JWT的HttpOnly Cookie:

Response.Cookies.Append("jwt", jwt, new CookieOptions { HttpOnly = true, Secure = true });

代码在两个环境中都是一样的,只是产生了不同的结果。在两种情况下,API会在身份验证响应头中向我发送正确的cookie,但是在生产环境中,我的react应用程序就是不会保持它,并在其他API调用中将其发送回来....

这里是从API收到的未被Web应用程序发送回的cookie:

Access-Control-Allow-Credentials    :true
Access-Control-Allow-Origin :https://xxxxxxxxxx.com
Connection  :keep-alive
Content-Type    :application/json; charset=utf-8
Date    :Mon, 09 Sep 2019 22:32:54 GMT
Server  :Kestrel
Set-Cookie  :jwt=xxxxxxxx; path=/; secure; samesite=lax; httponly
Transfer-Encoding   :chunked
Vary    :Origin
Via :1.1 vegur

如果有任何线索,我会永远感激。


也许你的生产服务器有一个指令类似于 Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure - 特别是它重写所有 cookie 为 HttpOnly - CrayonViolent
@Crayon Violent:你的意思是它必须要安全吗? - Binarynam
好的,在你的更新中,我看到了以下内容:Set-Cookie :jwt=xxxxxxxx secure; samesite=lax; httponly,所以我确实在你的cookie上看到了httponly标志。因此,你的客户端(js)代码无法读取/写入该cookie。 - CrayonViolent
httponly 的目的是 允许服务器读/写 cookie。这使得您的 cookie 更加安全,没错。但重点是带有此标志的 cookie 无法被客户端代码读取/写入,而这正是您正在尝试做的事情。您确定您的开发环境包括此标志吗?因为没有任何方法可以使用此标志读取/写入 cookie。 - CrayonViolent
httponly是在设置cookie时设置的标志,与任何其他cookie设置(例如secure、domain、path、expire等)相同。问题不在于标志本身。听起来你的服务器代码和/或服务器配置有问题,没有设置它。你的代码甚至可能在开发环境和生产环境中是相同的,并且你的生产服务器可能单独具有一个服务器指令,重写所有cookie以包括它。但这只是一种猜测。我无法完全了解你的所有内容。但听起来你至少有些东西需要调查了。 - CrayonViolent
显示剩余8条评论
1个回答

2

好的,结果证明我的很多事情都错了:

  • 我的Web应用程序代码一切正常。
  • 在开发环境中,一切都在localhost上运行(只是不同的端口),这符合samesite=lax(默认值)的cookie策略。
  • 为了使其跨域,你只需指定samesite=none,然后它就可以工作了。这会创建一些潜在的漏洞,因为你失去了一些对cookie的控制,但除非你设置一些反向代理/API网关机制,否则这是唯一可行的方法,至于cookie(包括httponly)来说。
  • 我对“jwt仅应存储在httponly cookie”规则过于兴奋:它也存在漏洞,你仍然需要让你的应用程序在xss(和其他技术)方面安全。如果你采取所有必要的预防措施,你可以安全地将jwt存储在本地存储中。

感谢@Crayon Violent的时间:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接