目录

JWT 的应用场景思考

目录

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

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

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) 

https://cdn.jsdelivr.net/gh/dfface/img0/0/M9zZa6-lAqbEz.jpg

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

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

安全问题:例如 CSRF ,解决方案是禁止跨域请求和同源检测,数据的传输还应该是 HTTPS 的。

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

AWS 方式

Microsoft 方式

Auth0 方式

参考文献:

Introduction to JSON Web Tokens

从JWT到CSRF

前后端分离之JWT用户认证

JSON Web Token 入门教程

JWT 的好处就是服务器不用存储客户端的任何信息,是无状态的,它相当于把 Session 应存储的东西利用 CPU 算力转化了,每次只需要验证签名即可。现在接着 JWT 引出的问题,如何解决?我们推荐在应用程序上使用 JWT ,往往使用多个令牌,例如各大厂商使用的“ID Token + Access Token + Refresh Token”。

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

{
  "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 持票人已经被授权。不得将访问令牌用于身份验证,访问令牌无法确定用户是否已通过身份验证。

{
  "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"
}

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

  • 一次性验证,例如邮件注册的链接等

  • RESTful 资源请求(跨服务器)

  • APP 的身份验证

  • cookie 中【不推荐】

  • localStorage 中【不推荐】

  • 访问令牌(内存中),刷新令牌(cookie中)【推荐,关键 操作二次验证】

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

在實際專案上導入JWT必須在安全性方面有許多的考量,除了微服務這種可能跨多伺服器的架構外,多數情境下,傳統的session與cookies都能取代JWT,並且更加成熟與安全

JWT開啟了一個新的大門,讓我們有新的方法去實現微服務、服務叢集、分散式服務系統、SPA、行動裝置手機應用情境。但我們必須了解其特性與原理,才能判斷適合的應用情境,若單純只把JWT視為取代session或cookie的新方法,就容易忽略其技術特性所帶來的安全風險。

就我看來,JWT並不是用來取代cookies與session的,而是在特定應用情境下一種新的操作權限的授與方法,如《Stop using JWT for sessions》的作者joepie91所述:

To be clear: This article does not argue that you should never use JWT - just that it isn’t suitable as a session mechanism, and that it is dangerous to use it like that. Valid usecases do exist for them, in other areas. At the end of this article, I’ll briefly go into those other usecases.

joepie91說本文要旨並不是要你永遠不該使用JWT,而是他並不適合作為session機制,而且將JWT代替session是有許多潛在的風險性的。也說:

A lot of people mistakenly try to compare “cookies vs. JWT”. This comparison makes no sense at all, and it’s comparing apples to oranges - cookies are a storage mechanism, whereas JWT tokens are cryptographically signed tokens.

cookies是儲存機制,不應該跟JWT進行類比,實際上session、cookie、JWT並不是對立關係,是可以一起使用或獨立使用的。

来自此视频(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中)

参考文献:

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

MDN Cookie

HTML5 本地存储 localstorage 安全分析

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

JWT 超详细分析