基本概念
认证(你是谁?)
- 用户通过手动的方式认证自己的身份
- 用户名/id+密码
- 短信验证
- 邮箱验证
- OAuth 2.0(三方授权)
- 一键登录
- 扫码登录
- 人脸
- 指纹
他的目的是认证身份,认证成功后进行授权操作
授权(你能做什么?)
- 完成认证明确用户身份之后,我们要给用户赋予一些条件(比如不同用户可以更改个人的信息,管理员可以更改普通用户的信息)
授权的标志是发放与用户相关的凭证: cookie,session,token等
鉴权(真的是你吗?)
- 用户请求时验证用户的授权凭证(cookie,session,token…),确定用户的权限
权限控制(你是否允许这样做?)
- 根据鉴权的结果判断用户当前的操作是否合法
能不能去掉授权与鉴权?
- 可以
- 但是会出现一个问题是你的每一个操作都会让你输入一次密码(认证);用户的体验很差,基本不是特别敏感的操作(转账,交易)基本不会进行反复认证的
鉴权的方式
存储比对模式(有状态)
- 服务端储存(Redis)授权的凭证
- 用户请求携带凭证
- 鉴权: 服务器比对储存的凭证与用户携带的凭证
方案: cookie-session,Opaque Token
签名验证模式(无状态)
- 服务端将验证凭证进行加密,发送给客户端
- 客户端请求时携带凭证
- 服务端通过加密算法进行解密
方案: JWT
证书验证模式
方案: SPKI(Public Key Infrastructure)(ssh 的免密登录,GitHub 的 ssh 模式)
无状态(JWT)鉴权
- 好处: 节省空间(不用存)
- 坏处: 安全问题(盗号,无法强制下线)
无状态安全问题的解决方法
- 使用储存对比的模式
1. 黑名单
- 黑名单用户标记强制下线用户,每次检查用户是否在黑名单
存在的问题:
case:
- 假设 token 的有效期是 1 天;找回账号(改密码)用了 1h
- 这时用户要正常使用就需要移出黑名单
- 但是这时旧的 token 依旧有效
解决方案:
二次验证: 验证 token 的颁发时间与密码更新时间(如果 token 颁发时间小于密码更新时间,则 token 无效)
总结: 此方法太复杂,还不如直接使用 cookie-session/Opaque Token 模式进行验证方便
2.使用 cookie-session (web)或者 Opaque Token(app) 模式鉴权
- 服务端储存颁发的请求凭证(token/session)与用户信息(Redis)
- 鉴权时对比客户端的凭证与服务端是否一致
盗号问题: 删除服务端的储存,即可限制用户访问,达到强制下线的目的
成本估算:
条件: 100万总 QPS;每台 Redis 2000 元/月
- 每次都要查询Redis,Redis 压力 100 万
- Redis 最高 10 万 QPS; 按 50%(安全范围)cpu 使用率,每台 Redis 承担 5 万 QPS
- 需要机器: 20 台
- 成本: 4 万/月
3. 无状态验证(jwt)与储存对比验证(cookie-session/Opaque Token)结合的模式
- 受到双刷 token 方案的启发
- 但是双刷 token 方案无法避免刷新 token 泄露的安全问题
我的调整: 将刷新 token 改为一个sessionId/Opaque Token(Redis储存)
工作原理:
- 登录时颁发 token 与 sessionId /Opaque Token(同时储存到 Redis)
- 正常 token有效期 5s
- 当正常 token 失效使用 sessionId/Opaque Token 刷新正常 token
盗号问题:
- 当 token 泄露: 因为是短期的,对方拿到就失效了,没有什么影响
- 当 sessionId 泄露: 清除 Redis 储存
- 当密码泄露: 将用户状态改为异常,限制用户的登录行为;再清除 Redis 的储存
成本估算
条件: 100万总 QPS;每台 Redis 2000 元/月
- 无状态验证不需要走 Redis,token 有效期 5s,相当于5s 查询一次 Redis,Redis 压力 20 万
- Redis 最高 10 万 QPS; 按 50%(安全范围)cpu 使用率,每台 Redis 承担 5 万 QPS
- 需要机器: 4 台
- 成本: 8000 /月