JWT 的应用场景思考:令牌应存放在浏览器何处?

什么是 JWT ?

JWT,全称 JSON Web Token。是一种开放标准,用于在各方之间安全传递信息,它是以 Base64 编码 json 对象的 token 。基于 token 的权限验证,与传统的 Session 认证完全不同,它不需要服务端保持 Session 记录,连用户状态都不需要关心。一旦用户登录网站,服务器就会生成 token,之后客户端每次登录时在HTTP的头信息中带上 token 即可。

由三部分(Base64)构成:<header>.<payload>.<signature>

1
2
3
4
5
6
header = '{"alg":"HS256","typ":"JWT"}'
payload = '{"sub":"admin","iat":1422779638}'//iat表示令牌生成的时间
key = 'secretkey'  
unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload)  
signature = HMAC-SHA256(key, unsignedToken)
token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature) 

M9zZa6-lAqbEz

应用场景:一次性验证,如注册邮件激活;RESTful API 的无状态认证;单点登录和会话管理。

缺点:一旦颁发,在其规定的时间内就一直有效,服务器不能提前终止(你可以在数据库里保存 token 并标记,但这违反了 jwt 的设计原则);令牌更新机制还有待商榷(续签问题)。

根据网友的讨论,“jwt 除了后端禁用外其他都可以实现到”,“JWT 的过期和刷新也很好做,参考业界主流做法,AWS、Azure 和 Auth0 都是用 JWT 为载体,ID Token + Access Token + Refresh Token 的模式”。

业界主流的三大令牌

JWT 的好处就是服务器不用存储客户端的任何信息,是无状态的,它相当于把 Session 应存储的东西利用 CPU 算力转化了,每次只需要验证签名即可。如何刷新和续签 Token ?业界主流做法是使用“ID Token + Access Token + Refresh Token”。

ID 令牌

ID Tokens 仅供应用程序使用,其中包含用户信息(名称和个人资料等),但不得用于访问 API。根据OpenID Connect规范,ID令牌的受众(由aud声明表示)必须是发出身份验证请求的应用程序的客户端ID

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "iss": "http://YOUR_DOMAIN/",
  "sub": "auth0|123456",
  "aud": "YOUR_CLIENT_ID",
  "exp": 1311281970,
  "iat": 1311280970,
  "name": "Jane Doe",
  "given_name": "Jane",
  "family_name": "Doe",
  "gender": "female",
  "birthdate": "0000-10-31",
  "email": "janedoe@example.com",
  "picture": "http://example.com/janedoe/me.jpg"
}

访问令牌

Access Tokens (并不总是 JWT),用于告知 API 持票人已经被授权。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "iss": "https://YOUR_DOMAIN/",
  "sub": "auth0|123456",
  "aud": [
    "my-api-identifier",
    "https://YOUR_DOMAIN/userinfo"
  ],
  "azp": "YOUR_CLIENT_ID",
  "exp": 1489179954,
  "iat": 1489143954,
  "scope": "openid profile email address phone read:appointments"
}

刷新令牌

刷新令牌是一种特殊的令牌,可用于获取更新的访问令牌。刷新令牌应由应用程序安全地存储,因为它们本质上允许用户永远保持身份验证。此敏感信息应安全地存储,而不应在浏览器的客户端公开。

JWT 存在哪里?

  • 全部存 cookie 中【不推荐,访问令牌必须能拿到,则有可能造成 XSS 攻击,且限制大小浪费带宽】
  • 全部存 localStorage 中【不推荐,本地存储不应存放任何机密信息,因为任何脚本都可以轻易拿到】
  • 访问令牌(内存中),刷新令牌(cookie中)【推荐,关键 操作二次验证】

来自:淺談JWT的安全性與適用情境

使用 JWT 同时 解决 XSS 与 CSRF

来自此视频(YouTube,翻墙可显示)下的评论:

The fix is simple; scope the cookie to only the path for requesting a new access token. This keeps all the benefits described of access token in memory, refresh token in cookie, and avoids having the refresh token "hanging around" where it shouldn't be (e.g. API requests that may dump the request to logs, leaking the long lived refresh tokens)

一句话:将cookie限定为仅用于请求新访问令牌的路径,即访问令牌(内存中),刷新令牌(cookie中)


AWS 方式

Microsoft 方式

Auth0 方式

Introduction to JSON Web Tokens

从JWT到CSRF

前后端分离之JWT用户认证

JSON Web Token 入门教程

前后端分离,使用JWT做状态保持,实现和传统session一致的效果

MDN Cookie

HTML5 本地存储 localstorage 安全分析

CSRF攻击与防御(写得非常好)

JWT 超详细分析

updatedupdated2020-07-122020-07-12
加载评论