几种鉴权方案

鉴权也叫身份验证(Authentication),是指验证用户是否拥有访问系统的权利。在日常的生活中,身份验证随处可见,比如:进入高铁站候车室、机场候机楼需要检查票据和身份证件;游玩主题乐园、名胜风景区需要购买门票,并由入口处人员鉴定有效后方可拥有进入园区游玩的权利。

面试时提到但经常叙述不清,开个专栏记录下。

同时在服务端设置session以及浏览器端设置cookie;

session可以保存在内存中,也可以保存在redis;

首次访问时在服务端创建session,该session有一个唯一的标识字符串,然后再set-cookie中设置该唯一字符串(sid);session的内容包括用户角色、登录时间等。

服务器接受客户端请求时解析cookie中的sid,然后去寻找有无对应session,判断该请求是否合法。

中间可以对sid进行加密处理(签名)

阮一峰-数字签名是什么

弊端:session消耗服务器内存

cookie容易受到CSRF攻击

Token

Token 认证流程图

流程:

  1. 用户输入登录信息并请求登录
  2. 服务端收到请求,验证用户输入的登录信息
  3. 验证成功后,服务端会 签发一个 Token(通常包含用户基础信息、权限范围和有效时间等),并把这个 Token 返回给客户端
  4. 客户端收到 Token 后需要把它存储起来,比如放在 localStorage 或 sessionStorage 里(一般不放 Cookie 因为可能会有跨域问题,以及安全性问题)
  5. 后续客户端每次向服务端请求资源的时候,将 Token 附带于 HTTP 请求头 Authorization 字段中发送请求
  6. 服务端收到请求后,去校验客户端请求中 Token,如果验证成功,就向客户端返回请求的数据,否则拒绝返还(返回401)

优点:

  • 服务端无状态:Token 机制在服务端不需要存储会话(Session)信息,因为 Token 自身包含了其所标识用户的相关信息,这有利于在多个服务器间共享用户状态
  • 支持移动设备(因为移动设备没有cookie)
  • 支持跨域跨程序调用,因为 Cookie 是不允许跨域访问的,而 Token 则不存在这个问题
  • 有效避免 CSRF 攻击(因为不需要 Cookie),但是会存在 XSS 攻击中被盗的风险,但是可选择 Token 存储在标记为 httpOnly 的 Cookie 中,能够有效避免浏览器中的 JS 脚本对 Cookie 的修改

缺点:

  • 占带宽:正常情况下比 sid 更大,消耗更多流量,挤占更多宽带。(几乎可以忽略)
  • 性能问题:相比较于 Session-Cookie 认证来说,Token 需要服务端花费更多时间和性能来对 Token 进行解密验证,其实 Token 相较于 Session—Cookie 来说就是一个时间换空间的方案
  • 由于服务器不保存session,因此一旦签发就无法修改权限,及有效期限;
  • 为了减少盗用机会,JWT不应该使用http,应该使用https

JWT

阮一峰-JWT入门

服务器认证后生成一个JSON对象,签名后发送回用户;

结构:

Header.Payload.Signature

是一个完整的JSON对象

header描述JST的元数据,包括alg签名使用的算法,typ表示token类型;使用时用base64URL转化成字符串

Payload

也是一个JSON对象,用来存放实际要传递的数据

JWT提供了7个官方字段:

1
2
3
4
5
6
7
iss (issuer):签发人
exp (expiration time):过期时间
sub (subject):主题
aud (audience):受众
nbf (Not Before):生效时间
iat (Issued At):签发时间
jti (JWT ID):编号

也可以定义私用字段;

也用base64URL转成字符串

Signature

使用Header中指定的算法进行签名;

1
2
3
4
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

Base64和Base64URL

前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

优缺点同上述token;

主动让JWT失效的方法

目前常见的处理方法有:

  • 1,将 token 存入 DB(如 Redis)中,失效则删除;但增加了一个每次校验时候都要先从 DB 中查询 token是否存在的步骤,而且违背了 JWT 的无状态原则(不推荐)。
  • 2,维护一个 token 黑名单,失效则加入黑名单中(用的比较多)。
  • 3,在 JWT 中增加一个版本号字段,失效则改变该版本号。
  • 4,在服务端设置加密的 key 时,为每个用户生成唯一的 key,失效则改变该 key。

其中,124都需要在服务器存储状态,3利用JWT可以传输数据的特点;

实际工程中2使用比较多,开销比较小

关于 token 的存储问题

JWT:

csrf 攻击无法获取第三方的 cookie,而是利用了“使用带有cookie的客户端进行查询的时候会自动携带 cookie”的特点。

xss攻击通过代码注入可以获取 cookie。需要设置转义。

方式一、客户端使用 cookie直接认证,需要设置 cookie为 httpOnly,可以防止 xss攻击。但是无法防止 csrf攻击。需要设置伪随机数 X-XSRF-TOKEN。(推荐!不 需要处理 xss,并且xsrf 随机数有完善的应用机制)

方式二、 客户端使用 auth授权头认证,token存储在 cookie中,需要防止xss攻击。可以防止 csrf攻击,因为 csrf只能在请求中携带 cookie,而这里必须从 cookie中拿出相应的值并放到 authorization 头中。实际上cookie不能跨站(同源政策)被取出,因此可以避免 csrf 攻击。(适用于 ajax请求或者 api请求,可以方便的设置 auth头)

方式三、可以将token存储在 localstorage里面,需要防止xss攻击。实现方式可以在一个统一的地方复写请求头,让每次请求都在header中带上这个token, 当token失效的时候,后端肯定会返回401,这个时候在你可以在前端代码中操作返回登陆页面,清除localstorage中的token。(适用于 ajax请求或者 api请求,可以方便的存入 localstorage)

设置 HTTPS,可以防止提交时的用户名或者密码被拦截或读取。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×