使用 JWT 保证 API 安全

why JWT

现在,前后端分离和 RESTful API 越来越火热,当后台渐渐开始只负责为客户端提供 API 接口之后,身份校验和接口安全成了难题。在传统的开发模式下,使用 cookie-session 可以保证接口安全,在没有登录的情况下访问关键数据会跳转到登录界面或者请求失败。而使用 REStful API 之后,cookie-session 存在以下 3 个问题:

正是存在上面的几个缺陷,现在 API 开始使用 JWT 代替 cookie-session 来做身份验证。

what JWT

JWT 全称 JSON Web Token。本质上 JWT 是一串 token 字符串。客户端登录之后,服务端返回一串 token 给客户端,之后每次客户端请求 API 接口都需要携带该 token 进行身份校验。JWT 由三个部分组成:头部(header)、载荷(payload)、签名(signature)。这三个部分使用 . 连接在一起就是一个完整的 JWT。所以,一个完整的 JWT 应该类似下面这种形式:

xxxxxx.yyyyy.zzzzz

header 是一个 json 数据,用于描述 JWT 的基本信息。一般要由两个部分组成:

alg 代表的是加密所使用的算法(后面会提到加密数据),typ 表示该 token 是什么类型的。这里 typ 自然是 JWT。

{
    'alg':'HS256',
    'typ':'JWT'
}

一个完整的 header 信息。最后使用 Base64 对 header 进行编码,得到 JWT 的第一部分。

payload

payload 是 JWT 存储信息的部分。payload 也是一个 json 数据,每一个 json 的 key-value 称为一个声明。

payload 有两种类型的声明:标准声明和自定义声明。

标准声明一共有 6 个,其名称和对应含义如下:

自定义声明为用户自己定义的 key-value,可以用来存储一些简单的基本信息。考虑到性能,不应该在 payload 中定义太多自定义声明。

定义一个 payload :

{
    "iss": "jaychen",
    "iat": 1441593502,
    "exp": 1441594722,
    "aud": "jaychen.cc",
    "sub": "chenjiayaooo@gmail.com",
    "jti:" "xxxxxxxx",

    "user_id": "1",
    "username": "jaychen"
}

上面这个 payload 中,idusername 为自定义声明。

有了 payload 只有,将该 payload 进行 Base64 加密,得到一串字符串之后,用 . 把 header 和 payload 连接起来。

signature

将 header 和 payload 两个部分连接起来之后,得到的字符串类似下面

xxxxx.yyyyy

接着,使用 header.alg 定义的加密算法对 hader.payload 的字符串进行加密,并且加密的时候应该有一个密钥。加密之后,得到一串加密字符串,最后把这串加密字符串也是用 . 拼接在 header.payload 后面,形成完整的 JWT。

这里签名的目的是为了保证 payload 数据的完整性。如果 JWT 在传输过程中被第三方劫持,中间人对 header.payload 进行修改,并且使用自己的密钥重新签名。服务端收到中间人修改过的 JWT,使用自己的密钥对 header.payload 进行再次加密,由于中间人和服务端使用的是不同的密钥签名,所以服务端再次加密的结果肯定和中间人加密的结果不一致,由此可以断定该 JWT 被恶意篡改。

基于 JWT 的身份验证

现在已经明白了 JWT 的生成过程,现在来梳理下 JWT 的使用流程。

JWT 的优点和注意事项

注意事项

上面生成 JWT 的过程中使用了 Base64 的加密算法对 payload 进行加密,Base64 是一种可逆的加密算法,这意味着其他人可以轻易的从加密结果中得到加密之前的信息,所以这注定了 payload 中不能保存密码之类的敏感信息。

优点

回顾上面生成 JWT 的步骤,payload 中我们保存了 user_idusername 这样的信息。在传统的 cookie-session 中,这些数据是服务端在 session 中维护的。JWT 把之前需要在服务端维护的 session 数据转移到客户端,使得服务端的压力小了很多。

JWT 本质只是一串字符串,所以可以无限制的使用各种姿势传递给服务端:当做 get 参数拼接在 URL 中、添加到 header 头部中、当做 post 参数传递。。。

如果客户端是手机 APP 等非浏览器客户端,那么使用 JWT 就可以免去对 cookie 的管理。

*****
Written by JayChen on 06 March 2019