具有基于HttpOnly cookie的身份验证和会话管理的单页应用程序

几天来,我一直在为我的单页应用程序寻找一种安全的身份验证和会话管理机制。从众多有关SPA和身份验证的教程和博客文章来看,将JWT存储在localStorage或常规Cookie中似乎是最常见的方法,但是使用JWT进行会话并不是一个好主意,因此,此应用程序不可行

要求

  • 登录名应该可以撤消。例如,如果在用户的帐户上检测到可疑活动,则应该可以立即撤消该用户的访问权限并要求重新登录。类似地,密码重置之类的操作也应撤消所有现有的登录名。
  • 认证应该通过Ajax进行。此后,不应再进行浏览器重定向(“硬”重定向)。所有导航都应在SPA内进行。
  • 一切都应该跨域工作。SPA将在www.domain1.com上,服务器将在www.domain2.com上。
  • JavaScript不能访问服务器发送的敏感数据,例如会话ID。这是为了防止XSS攻击,其中恶意脚本可以从常规cookie,localStorage或sessionStorage中窃取令牌或会话ID。

理想的机制似乎是使用HttpOnly包含会话ID的cookie的基于cookie的身份验证该流程将像这样工作:

  1. 用户到达登录页面并提交其用户名和密码。
  2. 服务器对用户进行身份验证并发送会话ID作为HttpOnly响应cookie。
  3. 然后,SPA在向服务器发出的后续XHR请求中包括此cookie。使用该withCredentials选项似乎可行
  4. 向受保护的端点发出请求时,服务器将查找cookie。如果找到,它将对照数据库表交叉检查该会话ID,以确保该会话仍然有效。
  5. 当用户注销时,将从数据库中删除会话。下次用户到达站点时,SPA会收到401/403响应(因为会话已过期),然后将用户带到登录屏幕。

由于cookie具有HttpOnly标志,因此JavaScript将无法读取其内容,因此只要通过HTTPS传输,它就不会受到攻击。

挑战性

Here's the specific issue I've run into. My server is configured to handle CORS requests. After authenticating the user, it correctly sends the cookie in the response:

HTTP/1.1 200 OK
server: Cowboy
date: Wed, 15 Mar 2017 22:35:46 GMT
content-length: 59
set-cookie: _myapp_key=SFMyNTYBbQAAABBn; path=/; HttpOnly
content-type: application/json; charset=utf-8
cache-control: max-age=0, private, must-revalidate
x-request-id: qi2q2rtt7mpi9u9c703tp7idmfg4qs6o
access-control-allow-origin: http://localhost:8080
access-control-expose-headers: 
access-control-allow-credentials: true
vary: Origin

However, the browser does not save the cookie (when I check Chrome's local cookies it's not there). So when the following code runs:

context.axios.post(LOGIN_URL, creds).then(response => {
  context.$router.push("/api/account")
}

And the Account page is created:

created() {
  this.axios.get(SERVER_URL + "/api/account/", {withCredentials: true}).then(response => {
    //do stuff
  }
}

This call does not have the cookie in the header. The server therefore rejects it.

GET /api/account/ HTTP/1.1
Host: localhost:4000
Connection: keep-alive
Accept: application/json
Origin: http://localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Referer: http://localhost:8080/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8,tr;q=0.6

Do I need to do something special to make sure the browser saves the cookie after receiving it in the login response? Various sources I've read have said that browsers save response cookies only when the user is redirected, but I don't want any "hard" redirects since this is an SPA.

The SPA in question is written in Vue.js, but I guess it applies to all SPAs. I'm wondering how people handle this scenario.

Other stuff I've read on this topic:

卡卡西Stafan2020/03/11 23:23:02

使用凭据控件设置和发送cookie,因此请确保在发布登录时将其打开,以便将返回的cookie保存在浏览器中。