阅读 914

JWT(JSON Web Token) 原理简析

简述

用一句话来说明JWT的原理其实很简单。写过API的同学应该会熟悉为了防止API被非法调用,会引入参数签名。最简单的方法就是把各种参数拼成字符串,再加一个密钥,最后做一个MD5作为签名。只要请求来的签名不符就可以认为参数被恶意篡改过。JWT就是将这件事情规范下来了。JWT的header部分说明如何进行签名,payload部分就是参数,signature部分就是签名。然后为了URL安全,把整个数据做base64即可。

详解

最近在想做一个OAuth2的API接口,但是几乎所以OAuth2的例程都会扯出另一个概念就是JWT (JSON Web Token),他跟OAuth2有关系吗?深入了解之后,发现他们其实并没有很强的关联,那么JWT到底是什么呢?

简单说,JWT是一个身份认证协议(protocol),他的优点是简单和对URL安全。另一个优势是可使服务器免除session存取的压力,同时在集群机或多子站上面,也免除了session需要同步的烦恼。

以下是JWT认证方式的一个简图

jwt-diagram

其实我觉得JWT在浏览器环境下与传统的cookie-session方式非常类似,服务器在验证身份之后产生一个cookie与session的关联,即session id,cookie给浏览器存储,session由服务器保存,当需要身份验证时则通过键为session id的cookie获取session,如果拿到正确的session数据则认证成功。

JWT的验证方式中,JWT即扮演cookie的角色(浏览器上通常就是把JWT存cookie)。客户端在需要身份认证的时候则传回JWT,区别就在于服务器端,此时的服务端并不需要通过session来获得身份信息,而是直接提取JWT中的信息。也就是说JWT不是一个简单的token,而是可以把信息(Json格式)编码进去的数据。服务器验证签名相符则表示可使用其携带的数据,否则认证失败。因为信息被编码在JWT中,所以可以免去session查询的消耗。而JWT中的数据需要通过对比签名来确保正确,签名需要的密钥当然只能存在服务器端了。把JWT的下发和验证逻辑都在服务端处理,这是保证安全的关键。

说简单一点就是把原本要存session的数据打包进cookie,然后搞个签名来验证一下数据的正确性即可。

实现方法

首先举个栗子,这是一个JWT。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

它是以下三块数据通过base64之后拼接而成的。

header.payload.signature

下面分别说明

头部(header)

{
    "alg" : "AES256",
    "typ" : "JWT"
}
复制代码

alg用来声明用何种哈希算法,细节见下。

荷载(payload)

荷载就是携带的数据,有部分官方定义的标准字段,也可以加入自己的数据。

{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
复制代码

其中sub是标准字段,常用的标准字段有

  • iss: 该JWT的签发者
  • sub: 该JWT所面向的用户
  • aud: 接收该JWT的一方
  • exp(expires): 什么时候过期,这里是一个Unix时间戳
  • iat(issued at): 在什么时候签发的

name,admin都是自定义的数据,这里可以加入任何内容,但是注意这些数据都是公开的,不可以加入敏感信息。

这个例子有个安全隐患就是没有设置有效期,这样便可以无限制使用了。应该加上exp或iat。

签名(signature)

这便是JWT认证的安全核心。因为base64编码基本等于公开,也很容易被篡改,如何保证可信。那就在签名上面。签名是头部(header)、荷载(payload)与一个密钥产生的哈希值。纵然前面的数据很容易被篡改,可是如果不知道签名的密钥则很难保证签名正确。

几个安全要点

  1. 不要加入敏感信息在荷载数据中,因为base64可以无障碍解码。
  2. 密钥一定保管好,只能存在服务器。因为安全的核心在签名,签名的核心在密钥。
  3. 荷载中要加入过期时间或生成时间。因为服务器不储存状态(这也是JWT认证的一个特点),所以无法判断它的有效期。
  4. 为防止XSS如果JWT是存Cookie最好为cookie加HttpOnly属性。

后记

说JWT与Oauth2没啥关系,是因为JWT只是一种token的协议,而Oauth2是一整套的认证逻辑。也许因为在API环境中也是没法使用传统的session,基于这个特点,大部分的Oauth2都使用JWT作为Oauth2的令牌,以是义故,Oauth2与JWT又结下了难解之缘。

文章分类
后端
文章标签