理解并使用 JWT
date
Nov 3, 2017
slug
understand-jwt
status
Published
tags
Auth
HTTP
summary
type
Post
JWT 简介
JWT(JSON Web Token) 是一个基于 JSON 的开放标准,它允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。
JWT 本质上就是一串字符串,它由
- Header
- Payload
- Signature
这三个部分组成,每个部分之间使用
.
进行分隔。关于 JWT 的更多介绍可见 https://jwt.io/introduction/
JWT 使用流程
整个流程图很清晰明朗,但是在第三步和第四步之间,客户端是需要保存用户状态的,那么JWT 是如何存储在客户端的呢?
浏览器端 JWT 存储方案
1. HTML5 WebStorage: localStorage or sessionStorage
使用这种方案时,服务端一般将
token
放入response body
中发送给客户端:HTTP/1.1 200 OK
{
"token":"eyJhbGciOiJIUzI1R5cCIpXVCJ9.eyJpZCI6MSwiZW1W4MIjcwMDk2fQ.aYC_idpEATBit6QmOiNSTn_SY8v0o"
}
localStorage 和 sessionStorage 是 HTML5 的特性,使用起来非常简单。
localStorage.setItem('token', response.body.token);
2. Cookie Storage
Cookie 的工作机制是用户识别及状态管理。调用 Cookie 时,由于可校验 Cookie 的有效期,以及发送方的域、路径、协议等有效信息,所以正规发布的 Cookie 内的数据不会因来自其他站点和攻击者的攻击而泄露。为 Cookie 服务的 HTTP header 有以下两种:
字段名
说明
header 字段类型
验证用户信息成功后,服务端会将 JWT 放在HTTP header 中的
Set-Cookie
字段HTTP/1.1 200 OK
Set-Cookie: access_token=eyJhbGciOiJIUzI1R5cCIpXVCJ9.eyJpZCI6MSwiZW1W4MIjcwMDk2fQ.aYC_idpEATBit6QmOiNSTn_SY8v0o; Secure; HttpOnly;
这样一来,当客户端向服务端发送请求时,请求中的
Cookie
字段会包含从服务端接收到的Cookie
。Which one is better?
使用 WebStorage 存储
token
,那么任何运行在该网站上的 JS 代码都可以访问到token
。如果网站遭到 XSS 攻击,那么用户信息就变得不安全了。所以包括 White Hat 在内的很多组织都建议不要将一些重要信息存储在 localStorage 和 sessionStorage 中。另外,在传输用户信息和 JWT 的过程中,数据也不是安全的,所以最好能将 Web 应用的升级成 HTTPS,使用 SSL 对通信进行加密。使用
HttpOnly
属性的 cookie,是无法被 JS 代码获取的。同时,给 Cookie 增加Secure
属性还可以确保 cookie 只能通过 HTTPS 传输。JWT 具有自包含的特性,所以携带 JWT 的 cookie 无需在服务端存储,开发者不必担心使用 cookie 会破坏 RESTful 的最佳实践。但是面对 CSRF 攻击,Cookie 也能被恶意窃取。默认情况下,无法通过 HTTP 跨域发送 cookie,若要跨域,需在Access-Control-Allow-Origin
字段中指定明确的域名。关于这两种方案的比较,这篇文章做了比较全面的描述:Where to Store Your Jwts
通过 Authorization Header 将发送 JWT
若使用 WebStorage 作为存储方案,那么就需要 JWT 就需要通过
Authorization
头字段来发送。Authorization 由两部分组成Authorization: <type> <credentials>
type 指的是验证类型,常见的有以下几种:
- Basic (see RFC 7617, base64-encoded credentials.),
- Bearer (see RFC 6750, bearer tokens to access OAuth 2.0-protected resources),
- Digest (see RFC 7616, only md5 hashing is supported in Firefox, see bug 472823for SHA encryption support),
- HOBA (see RFC 7486 (draft), HTTP Origin-Bound Authentication, digital-signature-based),
每个验证类型的不同之处在于它们的适用范围(客户端类型和服务端类型),以及它们的加密强度。
根据RFC,传输 JWT 选择的 Bearer 类型。JWT 与 类型之间以空格分隔。
Authorization: Bearer eyJhbGciOiJIUzI1R5cCIpXVCJ9.eyJpZCI6MSwiZW1W4MIjcwMDk2fQ.aYC_idpEATBit6QmOiNSTn_SY8v0o; Secure; HttpOnly;
Use JWT or not ?
在 JWT 之前,人们往往是通过 cookie + session 的方式来解决服务器如何识别用户的问题:
通过比较可以看出,使用 JWT 可以省去服务端读取 Session 的操作,它可以充分依赖无状态 API,更加符合 RESTful 规范。
看起来,JWT 十分美好。
但是!综合来看,还是有其局限性,已经有人呼吁停止将 JWT 用于会话机制。
Stop using jwt for sessions这篇文章将 JWT 的优劣分析的很详尽,也说明了 JWT 的真正使用场景。