理解并使用 JWT

date
Nov 3, 2017
slug
understand-jwt
status
Published
tags
Auth
HTTP
summary
type
Post

JWT 简介

JWT(JSON Web Token) 是一个基于 JSON 的开放标准,它允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。
JWT 本质上就是一串字符串,它由
  1. Header
  1. Payload
  1. Signature
这三个部分组成,每个部分之间使用.进行分隔。
关于 JWT 的更多介绍可见 https://jwt.io/introduction/

JWT 使用流程

notion image
整个流程图很清晰明朗,但是在第三步和第四步之间,客户端是需要保存用户状态的,那么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 字段类型
开始状态管理所使用的 Cookie 信息
响应字段
服务端接收到的 Cookie 信息
请求字段
验证用户信息成功后,服务端会将 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 的方式来解决服务器如何识别用户的问题:
notion image
通过比较可以看出,使用 JWT 可以省去服务端读取 Session 的操作,它可以充分依赖无状态 API,更加符合 RESTful 规范。
看起来,JWT 十分美好。
但是!综合来看,还是有其局限性,已经有人呼吁停止将 JWT 用于会话机制。
Stop using jwt for sessions这篇文章将 JWT 的优劣分析的很详尽,也说明了 JWT 的真正使用场景。

参考资料:

  1. JWT introduction
  1. Where to Store Your Jwts
  1. Stop using jwt for sessions

© Sytone 2021 - 2024