https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
reference:https://juejin.im/post/5d01f82cf265da1b67210869
JSON Web Tokens由dot分隔的三个部分组成:
Header(头部)
Payload(负载)
Signature(签名)
Header(头部)
Header 是一个 JSON 对象
{
"alg":"HS256",// 表示签名的算法,默认是 HMAC SHA256(写成 HS256)
"typ":"JWT"// 表示Token的类型,JWT 令牌统一写为JWT
}
Payload(负载)
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的数据
{
// 7个官方字段
"iss":"a.com",// issuer:签发人
"exp":"1d",// expiration time: 过期时间
"sub":"test",// subject: 主题
"aud":"xxx",// audience: 受众
"nbf":"xxx",// Not Before:生效时间
"iat":"xxx",// Issued At: 签发时间
"jti":"1111",// JWT ID:编号
// 可以定义私有字段
"name":"John Doe",
"admin":true
}
JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
非常重要提醒,token是通过 HMACSHA256 算法生成,header和payload是Base64URL编码,这不是加密。如果去访问jwt.io网站,粘贴token以及选择HMACSHA256算法,可以解析出token读取它详细的内容。因此里面不能携带一些敏感数据,比如密码,绝对不能存储在payload中。
如果必须存储敏感信息在payload中,或者使JWT被隐藏,可以使用JWE(JSON Web Encryption)。JWE允许你去加密JWT的内容,让其除了服务器以外的任何人都不可读。JOSE为 JWE提供了一个很好的框架,并为许多流行框架(包括NodeJS和Java)提供了SDK。
Signature(签名)
Signature 是对前两部分的签名,防止数据被篡改。
首先,需要指定一个密钥(secret),这个密钥只有服务器才知道不能泄露给用户。然后使用Header里面指定的签名算法(默认是HMAC SHA256)按照下面的公式产生签名。
$Signature=HMACSHA256(base64UrlEncode(header) +"."+ base64UrlEncode(payload), secret)
算出签名后把Header、Payload、Signature三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
JWT = Base64(Header) +"."+ Base64(Payload) +"."+ $Signature
如何保证安全?
1.发送JWT要使用HTTPS;不使用HTTPS发送的时候,JWT里不要写入秘密数据
2.JWT的payload中要设置expire时间
使用方式
客户端收到服务器返回的JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。此后客户端每次与服务端通信,都要带上这个JWT。你可以把它放在Cookie里面自动发送,但是这样不能跨域,所以更好的做法是放在HTTP请求的头信息Authorization字段里面。
Authorization: Bearer <token>
另一种做法是, 跨域的时候, JWT就放在POST请求的数据体里。
JWT 的作用
JWT最开始的初衷是为了实现授权和身份认证作用的,可以实现无状态、分布式的Web应用授权。
客户端需要携带用户名/密码等可证明身份的的内容去授权服务器获取JWT;
每次服务都携带该Token与Web服务器进行交互,由业务服务器来验证Token是否是授权发放的有效Token,来验证当前业务是否请求合法。
需注意:不是每次请求都要申请一次Token。如果不是对于安全性要求的情况,不建议每次都申请,因为会增加业务耗时;比如只在登陆时申请,然后用JWT的过期时间或其他手段来保证JWT的有效性。
Acesss Token,Refresh Token
JWT最大的优势是服务器不再需要存储Session,使得服务器认证鉴权业务可以方便扩展。这也是JWT最大的缺点由于服务器不需要存储Session状态,因此使用过程中无法废弃某个Token,或者更改Token的权限。也就是说一旦JWT签发了,到期之前就会始终有效。
基于上面提到的问题做一些改进。
前面讲的Token,都是Acesss Token,也就是访问资源接口时所需要的Token;还有另外一种Token,Refresh Token。一般情况下,Refresh Token的有效期会比较长;而Access Token的有效期比较短。当Acesss Token由于过期而失效时,使用Refresh Token就可以获取到新的Token;如果Refresh Token也失效了,用户就只能重新登录了。Refresh Token及过期时间是存储在服务器的数据库中,只有在申请新的Acesss Token时才会验证,不会对业务接口响应时间造成影响,也不需要向Session一样一直保持在内存中以应对大量的请求。
安全性
JWT签名旨在防止在客户端被篡改,但也可以对其进行加密,以确保token携带的claim非常安全。
JWT主要是直接存储在web存储(本地/session存储)或cookies中。JavaScript可以访问同一个域上的Web存储,这意味着你的JWT可能容易受到XSS(跨站脚本)攻击。恶意JavaScript嵌入在页面上,以读取和破坏Web存储的内容。事实上,很多人主张,由于XSS攻击,一些非常敏感的数据不应该存放在Web存储中。一个非常典型的例子是确保你的JWT不将过于敏感/可信的数据进行编码,例如用户的社会安全号码。
最初提到JWT可以存储在cookie中,cookies很容易受到CSRF(跨站请求伪造)攻击。预防CSRF攻击的许多方法之一是确保你的cookie只能由你的域访问。作为开发人员,不管是否使用JWT,确保必要的CSRF保护措施到位以避免这些攻击。
现在,JWT和session ID也会暴露于未经防范的重放攻击。建立适合系统的重放防范技术,完全取决于开发者。解决这个问题的一个方法是确保JWT具有短期过期时间。虽然这种技术并不能完全解决问题。解决这个挑战的其他替代方案是将JWT发布到特定的IP地址并使用浏览器指纹。
注意:使用HTTPS/SSL确保你的Cookie和JWT在客户端和服务器传输期间默认加密,这有助于避免中间人攻击。