Session-Cookie、Token、JWT
都是用于处理身份验证和授权的常见方式,下面是一般的应用场景:
- 使用
Session-Cookie
可能更适合传统的 Web 应用,其中服务器对状态的管理较为方便。 - 对于前后端分离的应用以及移动 APP 端,
Token
或JWT
是更常见的选择,它们具有无状态的特点,更适应分布式和可扩展的架构。
Session-Cookie
Cookie
是服务器发送到用户浏览器并保存在本地的小段文本信息。每次用户浏览相同的站点时,浏览器都会将 Cookie
发送回服务器,以便识别用户或获取之前存储的信息。
Session
是服务器端保存的关于特定用户会话的信息。与 Cookie
不同,Session
数据存储在服务器上,而客户端的 Cookie
中通常只包含一个用于检索 Session
的标识符。
而Session-Cookie
就是把 Session
的标识符存储在了客户端的 Cookie
中。
认证步骤解析
1.输入用户名/密码进行登录校验
2.通过校验后,服务器自动创建 Session(将 Session 保存在内存中,也可以保存在 Redis 中),然后给这个 Session 生成一个唯一的标识字符串会话身份凭证 session_id
,并在响应头 Set-Cookie
中设置这个唯一标识符;
- 注 :可以使用签名对
session_id
进行加密处理,服务端会根据对应的secret
密钥进行解密 (非必须步骤)
3.客户端收到服务器的响应后会解析响应头 ,并自动将 session_id
保存在 本地 Cookie 中,浏览器在下次 HTTP 请求时请求头会自动附带上该域名下的 Cookie 信息;
4.服务器接收客户端请求时会去解析请求头 Cookie 中的 session_id
,验证服务器中保存的 Session ,然后判断该请求是否合法;
Token 鉴权
Token
是一个令牌,客户端访问服务器时,验证通过后服务端会为其签发一张令牌,之后,客户端就可以携带令牌访问服务器,服务端只需要验证令牌的有效性即可。
相比于Session-Cookie
其最大优点在于:能有效避免 CSRF 攻击,以及支持跨程序调用(没有跨域问题)
Token 的一般组成: uid (用户唯一的身份标识) + time (当前时间的时间戳) + sign (签名,Token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
认证步骤
1.输入用户名和密码请求登录校验;
2.校验通过后,服务端会签发一个 Token
,并发送给客户端;
3.客户端收到 Token
以后需要把它存储起来,web 端一般会放在 localStorage 或 Cookie 中,移动端原生 APP 一般存储在本地缓存中;
4.客户端向服务端请求 API 资源的时候,将 Token
通过 HTTP
请求头 Authorization
字段或者其它方式发送给服务端;
5.服务器收到请求,然后去验证客户端请求里面带着的 Token
,如果验证成功,就向客户端返回请求的数据,否则拒绝返还(401);
Refresh Token(刷新 Token)
业务接口用来鉴权的 Token
,我们称之为 Access Token
,为了避免其被盗用,一般有效期会设置的较短;
而在Access Token
过期后,用于重新生成新的 Access Token
的 Token
,我们称为 Refresh Token
;
Refresh Token 认证步骤
1.登录校验;
2.校验通过后,服务端会签发一个 Access Token
和 Refresh Token
并返回给客户端;
3.客户端把 Access Token
和 Refresh Token
存储在本地;
4.客户端请求数据时,携带 Access Token
传输给服务端;
5.服务端:
- 验证
Access Token
有效:正常返回数据 - 验证
Access Token
过期:拒绝请求
6.Access Token
已过期,客户端则重新传输 Refresh Token
给服务端;
7.服务端验证 Refresh Token
,验证成功后返回新的 Access Token
给客户端;
8.客户端重新携带新的 Access Token
请求接口;
JWT(JSON Web Token)鉴权
服务端验证客户端发送过来的 Token
时,还需要查询数据库获取用户基本信息,这样增加了查库带来的延迟等性能消耗;
而JWT
通过 对 JSON 进行加密签名
来实现授权验证的方案可以解决这个问题。
具体地,JWT
由三部分组成: Header 头部
、 Payload 负载
和 Signature 签名
其认证过程大致如下:
- 登录成功后将相关用户信息组成
JSON
对象,然后对这个对象进行某种方式的加密
,返回给客户端; - 客户端在下次请求时带上这个
Token
; - 服务端直接解析
Token
中的payload
部分即可获得用户的身份信息。
避免 Token 泄露的方法
- 使用 HTTPS
- 考虑使用安全存储,如应用内存储(SecureStorage)或是加密存储库,以增加 Token 的存储安全性
- 设置较短的过期时间,并使用刷新令牌机制
- 实现反抓取和反爬虫机制
可能遭遇的网络攻击
XSS(跨站脚本攻击)和 CSRF(跨站请求伪造)对 Session-Cookie 和 Token 鉴权方案都会有威胁
XSS(跨站脚本攻击)
攻击者通过注入恶意脚本代码到网页中,从而在用户浏览器中执行这些脚本,以获取敏感信息,包括但不限于用户的身份认证 Token
。
为了防止 XSS 攻击,可以考虑以下措施:
- 对用户输入进行合适的验证和输出转义,以防止 XSS 攻击
- 使用 HttpOnly 标记设置 Cookie,这样浏览器将禁止通过 JavaScript 访问该 Cookie
- 使用 Secure 标记,确保令牌只在加密的 HTTPS 连接中传输
- 在服务器端设置合适的 CORS 头,限制哪些域可以访问资源
- 避免在前端存储敏感信息
CSRF(跨站请求伪造)
攻击者通过利用被害者在目标网站上的身份,以被害者的名义执行未经授权的操作。这种攻击通常涉及在用户不知情的情况下,向目标网站发送恶意请求。
1.SameSite Cookie 属性: 设置 Cookie 的 SameSite 属性,限制 Cookie 的发送
2.Anti-CSRF Token: 在每个请求中包含一个随机生成的 Anti-CSRF Token,服务器在接收到请求时验证 Token 的有效性
3.验证 Referer 头: 服务器可以验证请求的 Referer 头,确保请求是从合法的来源发起的。
4.限制敏感操作的 HTTP 方法: 将敏感操作限制为使用 POST 请求,因为大多数 CSRF 攻击是基于 GET 请求的。
5.使用双重身份认证: 引入双重身份认证,要求用户在执行敏感操作时再次输入密码或使用其他验证手段。