Cookie-session
我们都知道JWT一般用于用户登录等需要记住的操作,在谈论JWT之前就不得不谈谈以前的cookie-session登录了 。因为http协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录(也就是说你登陆过后哪怕你刷新一下他也不认识你了,还要你继续登录);Session 和 Cookie 的主要目的就是为了弥补 HTTP 的无状态特性。
互联网服务离不开用户认证,一般流程如下:
这就是Cookie-session方法
Session是什么
客户端请求服务端,服务端会为这次请求开辟一块内存空间
,这个对象便是 Session 对象,存储结构为 ConcurrentHashMap
。Session 弥补了 HTTP 无状态特性,服务器可以利用 Session 存储客户端在同一个会话期间的一些操作记录,如上图所示,我们在这个过程中会存储session_id。
cookie-session机制的缺点
扩展性(scaling)不好
单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。比如 A 服务器存储了 Session,在做了负载均衡后,假如一段时间内 A 的访问量激增,会转发到 B 进行访问,但是 B 服务器并没有存储 A 的 Session,会导致 Session 的失效。一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大(session存储在服务端,这就增大了服务器的开销,当用户多的情况下,服务器性能会大大降低)。另外,持久层万一挂了,就会单点失败。
另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端(一种非常重要的思想,让客户端帮我们存储或者做计算减少服务端的压力),每次请求都发回服务器。JWT 就是这种方案的一个代表。
安全性差:
Cookie安全性是一个大问题,因为它们是以明文形式存储,可能会造成安全风险,因为任何人都可以打开并篡改cookie。Cookie容易在客户端被发现意味着它们很容易被黑客入侵和修改。也就等于合法登陆了你的账户
JWT
JWT 的原理
服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。
以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名 。服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。
JWT的数据结构
实际的JWT就像这样
我们可以通过JSON Web Tokens - jwt.io 来解析JWT
它是一个很长的字符串,中间用点(.
)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。
JWT 的三个部分依次如下。
写成一行,就是下面的样子。
Header部分是一个JSON对象,描述JWT的元数据
payload部分也是一个json对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。
除了官方字段,你还可以在这个部分定义私有字段,下面就是一个例子。
注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
Signature 部分是对前两部分的签名,防止数据篡改。
JWT的使用方式
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。
此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization
字段里面。
另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。
JWT的特点
说完JWT,你可能还是会有疑惑,这不和cookie-session差不多吗?cookie-session返回session_id,JWT返回token,那你cookie可能会被截获并修改那你token就不会了吗?
事实上,JWT可以通过Signature字段来防止token被篡改。使用私钥加密生成token 公钥解密获取token中的信息
另一方面采用https 或者 代码层面也可以做安全检测,比如ip地址发生变化,MAC地址发生变化等等,可以要求重新登录
由于token生成后无法设置该token为无效,所以只能采用设置token过期时间来生成新的refresh_token。以及应该使用HTTPS协议传输(这些都是上图特点6的内容)
除了安全性,JWT还有什么好处吗?
JWT官方给出的解释是(对比SWT与SAML):
JWT由于使用的是JSON所以比较轻量:由于JSON不像XML那么冗长,所以在编码时,它的大小也更小,使得JWT比SAML更紧凑。这使得JWT成为在HTML和HTTP环境中传递的好选择。
安全性:SWT只能使用HMAC算法由共享密钥对称签名。然而,JWT和SAML令牌可以使用X.509证书形式的公钥/私钥对进行签名。与签名JSON的简单性相比,使用XML数字签名签名XML而不引入模糊的安全漏洞是非常困难的。
JSON在各种语言都能方便的解析:JSON解析器在大多数编程语言中都很常见,因为它们直接映射到对象。相反,XML没有自然的文档到对象映射。这使得使用JWT比使用SAML断言更容易。
跨平台性:JWT在互联网规模上使用。这突出了在多个平台(尤其是移动平台)上客户端处理JSON Web令牌的方便性。
参考资料:
基于Session的身份窃取 - 腾讯云开发者社区-腾讯云 (tencent.com)JSON Web Token 入门教程 - 阮一峰的网络日志 (ruanyifeng.com)
JSON Web Token Introduction - jwt.io
learn-json-web-tokens/README.md at master · dwyl/learn-json-web-tokens (github.com)