Web Security: Scenario: How to Store API Token at Browser?

 20th August 2020 at 2:19pm

这篇文章主要探讨 在带后台的 SPA 场景下,如何在浏览器上存储 API token?这里的 API token 指带有用户身份或者会话信息,需要在每次浏览器请求后台 API 时发过去的数据。不限制它的格式和用途,它可以是个 JWT,也可以是个 OAuth 的 access token。

浏览器中存储数据主要有两种方式,cookie 及 HTML5 Storage API(包含 localStorage 及 sessionStorage)。Cookie 虽然主要用于被服务端生成及读取,并不是提供给浏览器存放内容使用,但是它刚好适用于这个场景。这也意味着对于 HTML5 Storage,需要额外的编程实现去将它带给服务端(典型的场景是通过 Authorization 头),而 cookie 不需要。

按多个维度进行的对比如下:

因素CookieHTML Storage
受 XSS 影响?HttpOnly 的不受影响
受 CSRF 影响?实现得当时不受影响否,只有 同源 的 JS 代码才可访问
内容长度限制4096 字节每 cookie5Mb 数据每域名
会话相关机制没有,需额外编程实现
请求后台时自动带上?否,需额外编程实现;同时你也往往不想把整个 storage 上传,而是只传其中的部分 key

会话相关机制包括:

  • 会话是否应该在某个时间自动失效?比如用户登录 30 天后失效,需要重新登录
  • 会话有效期是否随用户使用而延长?比如已登录的用户每次打开页面做操作时,都自动把会话有效期延长到当前时间的 30 天后
  • 是否需要实现「记住我(remember me)」功能?虽然目前大部分服务默认是记住的

这些机制在 cookie 上都有成熟的实现;在 JWT 上虽然可以实现,但是框架支持程度不一,有可能需要额外的工作量。

总体来看 Cookie 看起来是实现成本比较低的方式。但是它需要有好的 防 CSRF 实现,特别是在目前(2020 年 4 月)SameSite 未普及的时候。

对于 HTML Storage 方式,如果你的前端框架做好了整合,使得实现成本不高时,感觉比 cookie 更加灵活和安全。

具体选择哪种方式,我觉得更看你使用的前后台技术栈(前台如 React、VueJS 等,后台如 Django、Lavavel 等)中框架和流行库的支持程度。