手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的( 三 )



手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

文章插图
JWT 的诞生并不是解决 CSRF 跨域攻击,而是解决跨域认证的难题 。
举例来说,A 网站和 B 网站是同一家公司的关联服务 。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,这应该如何实现呢?
一种解决方案是 session 数据持久化,写入数据库或别的持久层 。各种服务收到请求后,都向持久层请求数据 。这种方案的优点是架构清晰,缺点是工程量比较大 。另外,持久层万一挂了,就会单点失败 。
另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器 。
JWT 就是这种方案的一个优秀代表 。
手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

文章插图
 
JWT 如何生成?JWT 其实就是一个字符串,比如下面这样
 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
仔细观察,会发现它里面有三个 .,以.为分界,可以将 JWT 分为三部分 。
手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

文章插图
  1. 第一部分:头部(Header)
  2. 第二部分:载荷(Payload)
  3. 【手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的】第三部分:签名(Signature)

手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

文章插图
 
5.1 头部(Header)JWT 的头部承载两部分信息:
  • 声明类型:这里是 JWT
  • 声明加密的算法:通常直接使用 Hmac SHA256
完整的头部就像下面这样的JSON:
 {
"typ": "JWT",
"alg": "HS256"
}
然后将头部进行 Base64URL 算法编码转换,构成了第一部分
 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
 
5.2 载荷(Payload)载荷,同样也是个 JSON 对象,它是存放有效信息的地方,但不建议存放密码等敏感信息 。
JWT 规定了7个官方字段,供选用:
  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号
除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子 。
注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分 。
 {
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后将其进行 Base64URL 算法转换,得到 JWT 的第二部分 。
 eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
 
5.3 签名(Signature)Signature 部分是对前两部分的签名,防止数据篡改 。
首先,需要指定一个密钥(secret) 。这个密钥只有服务器才知道,不能泄露给用户 。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名 。
 HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户 。
手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

文章插图
 
如何手动生成 JWT?如果你想手动生成一个 JWT 用于测试,有两种方法
第一种:使用 https://jwt.io/ 这个网站。
我使用前面的 header 和 payload,然后使用 secret 密钥:Python
最后生成的 JWT 结果如下
 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.3wGDum3_A8tAt1bdal5CpYbIUlpHfPQxs96Ijx883kI

手绘10张图,把CSRF跨域攻击、JWT跨域认证说得明明白白的

文章插图
第二种:使用 Python 代码生成
首先安装一下 pyjwt 这个库
 $pip install pyjwt
然后就可以在代码中使用它
 import jwt
import datetime
import uuid
salt = 'minggezuishuai'
# 构造header ,这里不写默认的也是


推荐阅读