认证,作为应用系统的大门,也作为研发安全的第一道门槛,很多师傅们与研发人员都清楚,这里我想从综合研发、安全(含SDL、安全测试)的视角,聊一聊认证的内核,即cookie、session、token、jwt
原理
Cookie:
HTTP 是无状态的协议,即每次客户端和服务端会话完成时,服务端不会保存任何会话信息,同时每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态需要通过 cookie 或者 session 去实现。
cookie有以下两个特点:
- cookie 存储在客户端:cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。
- cookie 是不可跨域的:每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)。
下图是cookie的工作流程:
- 用户访问网站,浏览器向服务器发起请求。
- 服务器响应请求,并向浏览器发送Cookie。
- 浏览器接收到Cookie,并将其存储。
- 用户再次访问同一网站,浏览器会在请求中携带Cookie。
- 服务器接收到请求,验证Cookie的有效性。
- 如果Cookie有效,服务器提供服务或资源。
- 如果Cookie无效,服务器可能要求用户重新登录,并重新设置Cookie。
Session
和cookie一样,session 也是一种记录服务器和客户端会话状态的机制
- cookie存于客户端,session 是基于 cookie 实现的,session 存储在服务器端,sessionId 会被存储到客户端的cookie 中
session 认证流程:
- 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session
- 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器
- 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
- 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。
根据以上流程可知,cookie是session的载体,SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。
注:如果客户端禁用了 cookie,还可以通过 url 重写等方法传递 sessionId。
Cookie 和 Session 的区别
- 安全性:Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
- 存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。
- 有效期不同:Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
- 存储大小不同:单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。
Token(令牌)
Acesss Token
前面提到的cookie、session在浏览器中用到的比较多,而token则是在APP与API中用到的比较多。
- 简单 token 的组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
特点:
- 服务端无状态化、可扩展性好
- 支持移动端设备
- 安全,同时支持跨程序调用
token 的身份验证流程:
- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
- 客户端收到 token 以后,会把它存储起来,比如放在 cookie 里(这时cookie又是一个载体)或者 localStorage (一种在用户浏览器中存储数据的方式)里
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 token
- 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据
注:如果每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里
基于 token 的用户认证是一种服务端无状态的认证方式,即服务端不用存放 token 数据。和session的区别是用性能换存储,即用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库
token 完全由应用管理,所以它可以避开同源策略
Refresh Token
refresh token 是专用于刷新 access token的 token。即当token过期以后,为了用户体验问题,而承担认证责任的中方式,如果没有 refresh token,也可以刷新 access token,但每次刷新都要用户输入登录用户名与密码,用户体验会比较差。有了 refresh token,可以减少这个麻烦,客户端直接用 refresh token 去更新 access token,无需用户进行额外的操作。
Access Token 的有效期比较短,当 Acesss