JWT

基于Token的身份认证

Posted by Liao on 2019-10-12

JWT是什么

  • JWT本质是Token,用于验证身份的凭证。这个凭证能允许我们使用JWT在用户和服务器之间传递安全可靠的信息。

  • 是经过base64编码字符串。

Cookie-Session认证机制

​ 客户端(用户)通过用户名和密码进行身份认证,但是下回发请求的时候又得验证以下。

​ 解决的办法是,用户成功登录之后,会在服务器端产生一条记录(Session),说明这用户是谁,然后把session_id传给客户端,并存入用户的Cookie。下次用户向服务器发送请求时,只需携带着包含用户信息的Cookie,看能否在服务器中找到记录,若可以则通过了身份认证,则把用户请求的数据返回到客户端。

上面提到的Session,会存储在服务器磁盘、内存或者数据库中,我们需要期清理过期的Session。

优点
  • 可以主动清除session
  • session保存在服务器端,相对较为安全
  • 结合cookie使用,较为灵活,兼容性较好
缺点
  • 服务器压力大:每个用户在认证后,Session 信息都会保存在服务器的内存中,开销大。

  • 难以扩展:对于基于 Session 的分布式系统、集群,要实现负载均衡,需要做多机共享session机制,实现方法可将session存储到数据库中或者redis中,加大了对数据库额外的开销和维护。

  • 会有跨域问题

JWT身份认证

为什么要使用Token?
  • JWT本质是用于验证身份的凭证,这个凭证能允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
  • 信息基于 base64 编码转换为 ASCII 码,字节占用很小,便于传输。
  • 基于 Token 的鉴权机制保持了 HTTP 协议的无状态型,每次操作都会生成新的JWT,不需要在服务器端存储用户的记录,因此也没必要保存JWT,真正实现无状态,从而实现更简单的水平扩展。

  1. 客户端使用用户名和密码进行登录;
  2. 服务器端接收到请求后,取验证用户名和密码;
  3. 验证成功后,服务器会签发一个Token,再把Token签发到客户端;
  4. 客户端接收到Token之后,会存储到Cookie或者Local Storage;
  5. 客户端每次向服务器发出请求时,都要携带服务器端签发的Token;
  6. 服务器端接收到请求,去验证客户端携带的Token,如果验证成功,则返回客户端请求的数据。

Token的创建过程

​ JWT的Token由三部分组成:Header+Payload+Signature

1)Header 创建头部

Header 部分是一个 JSON 对象,描述 JWT 的元数据。

{
“alg”: “HS256”,
“typ”: “JWT”
}

alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(这个算法的密钥只有认证服务器和应用服务器知道),用什么 hash 算法来生成 JWT 签名模块(下文描述)。

typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。

2)Payload 创建负载

Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据。官方给出了json数据的字段。

{

​ “iss (issuer)”:签发人
​ exp (expiration time):过期时间
​ sub (subject):主题
​ aud (audience):受众
​ nbf (Not Before):生效时间
​ iat (Issued At):签发时间
​ jti (JWT ID):编号

}

当然,我们也可以自定义。

{
“exp”: “1234567890”,
“username”: “test”

}

注意一点,payload 是一定不能够携带敏感数据如密码等信息的

3)Signature 签名

签名的目的主要是为了验证我是 “我“,把前两部分(Header、Payload)和用户的密钥进行哈希,防止数据篡改。换言之,即使Header或Payload被篡改,但篡改者不知到密钥是什么,无法生成签名,形成Token,服务器端无法通过验证。

生成签名的步骤:

​ ①Base64URL对生成的 header 和 payload 进行 base64url编码,然后把编码生成的字符串中间通过句号(.)连接起来。

​ ②把密钥secret和data进行hash算法加密,生成签名,再进行base64编码,生成签名。(此处的secret是指用户的密钥,通过HA256或者其他方法进行加密)

HMACSHA256 ( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )

延伸:

加密认证

JWT的签名除了通过密钥(secret)的HMAC加密算法,还支持公钥或私钥的RSA or ECDSA算法。

加密方法

  1. 对称加密:指的就是加、解密使用的同是一串密钥,所以被称做对称加密。对称加密只有一个密钥作为私钥。
    常见的对称加密算法:DES,AES等。
  2. 非对称加密:指的是加、解密使用不同的密钥,一把作为公开的公钥,另一把作为私钥。公钥加密的信息,只有私钥才能解密。反之,私钥加密的信息,只有公钥才能解密。 最常用的非对称加密算法:RSA
4)三个模块合并成Token

产生签名之后,把Header、Payload、Signature 三个部分用 “ . ” 拼成一个字符串。

自此,用户得到了服务器返回的Token(凭证)。用户下次登录的时候,在过期时间之内或者注销会话之内,可以凭这这个Token免密登录。

5.校验JWT

​ 由于应用知道密钥,当用户向应用发起携带 JWT 的 API 请求时,应用可以执行签名算法。然后应用可以校验用户 hash 操作生成的签名是否和 JWT 中的签名匹配(即它匹配认证服务器创建的 JWT 签名),若匹配一致,则认证通过,返回请求的数据。

JWT适用场景

  • 做简单的 Restful API 认证,从RESTful API查询使用JSON数据。RESTful API的原则之一是它应该是无状态的,这意味着当发出请求时,总会返回带有参数的响应,不会产生附加影响。

  • 每次请求刷新 jwt。

缺点

JWT 本质上是通过时间换空间,服务器不存储用户状态信息,但是每个用户请求都会消耗 CPU 时间来验证 Token。

XSS攻击是恶意网页程序(通常是JavaScript)对网站进行攻击。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

服务器返回的Token是存储在客户端的Cookie或者Local Storage中,故容易发生XSS攻击。

注意

  • 为了防止中间人窃取Token,从而发生CSRF 攻击,使用https对请求进行加密传输。

  • JWT的信息是不加密存储的,不可存敏感信息。

  • 设置一个表较短的过期时间。JWT是安全,但也不是绝对的,比如针对同一个接口,JWT字符串被截取后,且在有效期内,在不篡改JWT字符串的情况下,也是可以模拟请求进行访问的。颁发一个有效期极短的JWT,即使暴露了危险也很小。

  • 生成签名字段时,支持使用密钥字符串签名(安全性较低),也支持使用 RSA、ECDSA 私钥签名。

https://juejin.im/entry/5bb211b7e51d450e5c478e0b