Web前端开发(8) 鉴权
前端鉴权
1. 基础知识
认证
- 认证(Identification) 是指根据声明者所特有的识别信息, 确认声明者的身份
- 比如我们常见的认证技术:
- 身份证、用户名和密码、用户手机: 手机短信、手机⼆维码扫描、手势密码、用户的电子邮箱、用户的生物学特征: 指纹、语音、眼睛虹膜、用户的大数据识别等等
授权
- 授权(Authorization) 在信息安全领域是指资源所有者委派执行者, 赋予执行者指定范围的资源操作权限, 以便对资源的相关操作
- 互联网领域授权的机制:
- web 服务器的 session 机制
- web 浏览器的 cookie 机制
- 颁发授权令牌(token)等
鉴权
- 鉴权(Authentication) 在信息安全领域是指对于一个声明者所声明的身份权利, 对其所声明的真实性进行鉴别确认的过程。
- 若从授权出发, 则会更加容易理解鉴权。授权和鉴权是两个上下游相匹配的关系, 先授权, 后鉴权。
- 在互联网领域: 校验 session/cookie/token 的合法性和有效性
- 鉴权是一个承上启下的一个环节, 上游它接受授权的输出, 校验其真实性后, 然后获取权限(permission), 这个将会为下一步的权限控制做好准备。
权限控制
- 权限控制(Access/Permission Control) 将可执行的操作定义为权限列表, 然后判断操作是否允许/禁止
- 对于权限控制, 可以分为两部分进行理解: 一个是权限, 另一个是控制。权限是抽象的逻辑概念, 而控制是具体的实现方式。
- 在互联网领域: 通过 web 后端服务, 来控制接口访问, 允许或拒绝访问请求
彼此关系
- 认证、授权、鉴权和权限控制这四个环节是一个前后依次发生、上下游的关系
2. HTTP 基本鉴权
HTTP 基本鉴权
- 在 HTTP 中, 基本认证方案(Basic Access Authentication) 是允许客户端(通常指的就是网页浏览器)在请求时, 通过用户提供用户名和密码的方式, 实现对用户身份的验证。
- 几乎所有的线上网站都不会走该认证方案
优缺点及场景
优点
- 简单, 基本所有流行的浏览器都支持
缺点
不安全:
- 由于是基于 HTTP 传输, 所以它在网络上几乎是裸奔的, 虽然它使用了 Base64 来编码, 但这个编码很容易就可以解码出来。
- 即使认证内容无法被解码为原始的用户名和密码也是不安全的, 恶意用户可以再获取了认证内容后使用其不断的向服务器发起请求, 这就是所谓的重放攻击。
无法主动注销:
- 由于 HTTP 协议没有提供机制清除浏览器中的 Basic 认证信息, 除非标签页或浏览器关闭、或用户清除历史记录。
使用场景
- 内部网络, 或者对安全要求不是很高的网络
3. Session-Cookie 鉴权
3.1 Cookie
- 众所周知, HTTP 是无状态的协议(对于事务处理没有记忆能力, 每次客户端和服务端会话完成时, 服务端不会保存任何会话信息)
- 所以为了让服务器区分不同的客户端, 就必须主动的去维护一个状态, 这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态可以通过 Cookie 去实现
关于 cookie
- cookie 对用户来说不是加密的
- 服务器向客户端发送的所有 cookie 都能被客户端查看, 绝没有加密那样的安全性。
- 用户可以删除或禁用cookie
- 用户对 cookie 有绝对的控制权, 并且浏览器支持批量或单个删除 cookie。
- 用户也可以禁用 cookie, 但这更容易造成问题, 因为只有最简单的 Web 应用程序才不需要依赖 cookie。
- Cookie 存储在客户端, 可随意篡改, 不安全
- 要确保 cookie 不被篡改, 请使用签名 cookie。
- cookie可以用于攻击
- 跨站脚本攻击(XSS)攻击中有一种技术就涉及用恶意的 JavaScript 修改 cookie 中的内容。所以不要轻易相信返回到你的服务器的 cookie 内容。
- 用签名 cookie 会有帮助(不管是用户修改的还是恶意 JavaScript 修改的, 这些篡改都会在签名 cookie 中留下明显的痕迹), 并且还可以设定选项指明 cookie 只能由服务器修改。这些 cookie 的用途会受限, 但它们肯定更安全。
- 有大小限制, 最大为 4kb
- 有数量限制, 一般一个浏览器对于一个网站只能存不超过 20 个 Cookie, 浏览器一般只允许存放 300个 Cookie
- Android 和 IOS 对 Cookie 支持性不好
- Cookie 是不可跨域的, 但是一级域名和⼆级域名是允许共享使用的(利用domain)
3.2 Session
- Session 的抽象概念是会话, 是无状态协议通信过程中, 为了实现中断/继续操作, 将用户和服务器之间的交互进行的一种抽象
- 具体来说, 是服务器生成的一种 Session 结构, 可以通过多种方式保存, 如内存、数据库、⽂件等, 大型网站一般有专门的 Session 服务器集群来保存用户会话
- 原理流程:
- 客户端: 用户向服务器首次发送请求
- 服务器: 接收到数据并自动为该用户创建特定的 Session / Session ID, 来标识用户并跟踪用户当前的会话过程
- 客户端: 浏览器收到响应获取会话信息, 并且会在下一次请求时带上 Session/Session ID
- 服务器: 服务器提取后会与本地保存的 Session ID 进行对比找到该特定用户的会话, 进而获取会话状态
- ⾄此客户端与服务器的通信变成有状态的通信
特点
- Session 保存在服务器上
- 通过服务器自带的加密协议进行
与 Cookie 的差异
- 安全性: Cookie 由于保存在客户端, 可随意篡改, Session 则不同, 存储在服务器端, 无法伪造, 所以 Session 的安全性更高
- 存取值的类型不同: Cookie 只支持字符串数据, Session 可以存任意数据类型
- 有效期不同: Cookie 可设置为长时间保持, Session 一般失效时间较短
- 存储大小不同: Cookie 保存的数据不能超过 4K
会话的用途
- 跨页保存用户的偏好
- 提供用户验证信息
- 登录后就会创建一个会话。之后就不用在每次重新加载页面时再登录一次。
- 即便没有用户账号, 会话也有用。
- 网站一般都要记住你喜欢如何排列东西, 或者喜欢哪种日期格式, 这些都不需要登录。
- 尽管建议优先选择会话而不是 cookie, 但理解 cookie 的⼯作机制也很重要(特别是因为有 cookie 才能用会话)。它对于你在应用中诊断问题、理解安全性及隐私问题都有帮助
3.3 Session-Cookie 鉴权
- Session-Cookie 认证是利用服务端的 Session(会话)和浏览器(客户端)的 Cookie 来实现的前后端通信认证模式。
优缺点及使用场景
Session-Cookie 的优点
- Cookie 简单易用
- Session 数据存储在服务端, 相较于 JWT 方便进行管理, 也就是当用户登录和主动注销, 只需要 添加删除对应的 Session 就可以了, 方便管理
- 只需要后端操作即可, 前端可以无感等进行操作
Session-Cookie 的缺点
- 依赖 Cookie, 一旦用户在浏览器端禁用 Cookie, 那么就无法使用了
- 非常不安全, Cookie 将数据暴露在浏览器中, 增加了数据被盗的风险(容易被 CSRF 等攻击)
- Session 存储在服务端, 增大了服务端的开销, 用户量大的时候会大大降低服务器性能
- 对移动端的支持性不友好
使用场景
- 一般中大型的网站都适用(除了 APP 移动端)
- 由于一般的 Session 需集中存储在内存服务器上(如 Redis), 这样就会增加服务器的预算, 所 以预算不够请谨慎选择
前端常用的 Session 库推荐
- 使用 express: express-session
- 使用 koa: koa-session
4. Token
4.1 Token(令牌)
- Token 是一个令牌, 客户端访问服务器时, 验证通过后服务端会为其签发一张令牌, 之后, 客户端就可以携带令牌访问服务器, 服务端只需要验证令牌的有效性即可
- 一句话概括, 访问资源接口(API)时所需要的资源凭证
- 一般 Token 的组成:
- uid (用户唯一的身份标识) + time (当前时间的时间戳) + sign (签名, Token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)
Token 的认证流程图
Token 的优缺点
Token 的优点:
- 服务端无状态化、可扩展性好: Token 机制在服务端不需要存储会话(Session)信息, 因为 Token 自身包含了其所标识用户的相关信息, 这有利于在多个服务间共享用户状态
- 支持 APP 移动端设备
- 安全性好: 有效避免 CSRF 攻击(因为不需要 Cookie)
- 支持跨程序调用: 因为 Cookie 是不允许跨域访问的, 而 Token 则不存在这个问题
Token 的缺点:
- 配合: 需要前后端配合处理
- 占带宽: 正常情况下比 sid 更大, 消耗更多流量, 挤占更多宽带
- 性能问题: 虽说验证 Token 时不用再去访问数据库或远程服务进行权限校验, 但是需要对 Token 加解密等操作, 所以会更耗性能
- 有效期短: 为了避免 Token 被盗用, 一般 Token 的有效期会设置的较短, 所以就有了 Refresh Token
4.2 Refresh Token (刷新Token)
- 业务接口用来鉴权的 Token, 我们称之为 Access Token
- 为了安全, Access Token 有效期一般设置较短, 以避免被盗用。但过短的有效期会造成 Access Token 经常过期, 过期后则:
- 一种办法是: 刷新 Access Token, 让用户重新登录获取新 Token, 会很麻烦
- 另外一种办法是: 再来一个 Token, 一个专门生成 Access Token 的 Token, 我们称为 Refresh Token
- Access Token: 用来访问业务接口, 由于有效期⾜够短, 盗用风险小, 也可以使请求方式更宽松灵活
- Refresh Token: 用来获取 Access Token, 有效期可以长一些, 通过独立服务和严格的请求方式增加安全性;由于不常验证, 也可以如前面的 Session 一样处理
Refresh Token 的认证流程图
Token 和 Session-Cookie 的区别
Session-Cookie 和 Token 有很多类似的地方, 但是 Token 更像是 Session-Cookie 的升级改良版
- 存储地不同: Session 一般是存储在服务端;Token 是无状态的, 一般由前端存储
- 安全性不同: Session 和 Token 并不⽭盾, 作为身份认证 Token 安全性比 Session 好, 因为每一个请求都有签名还能防止监听以及重放攻击
- 支持性不同: Session-Cookie 认证需要靠浏览器的 Cookie 机制实现, 如果遇到原生 NativeAPP 时这种机制就不起作用了, 或是浏览器的 Cookie 存储功能被禁用, 也是无法使用该认证机制实现鉴权的;而 Token 验证机制丰富了客户端类型
4.3 JWT(JSON Web Token)鉴权
- JWT 是 Auth0 提出的通过对 JSON 进行加密签名来实现授权验证的方案
- 就是登录成功后将相关用户信息组成 JSON 对象, 然后对这个对象进行某种方式的加密, 返回给客户端;客户端在下次请求时带上这个 Token;服务端再收到请求时校验 token 合法性, 其实也就是在校验请求的合法性
- JWT 由三部分组成: Header 头部、Payload 负载、Signature 签名
- 它是一个很长的字符串, 中间用点(.)分隔成三个部分。如:
- eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fw pMeJf36POk6yJV_adQssw5c
JWT 的使用方式
- 客户端收到服务器返回的 JWT, 可以储存在 Cookie 里面, 也可以储存在 localStorage
- 此后, 客户端每次与服务器通信, 都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送, 但是这样不能跨域, 所以更好的做法是放在 HTTP 请求的头信息Authorization字段里面
- Authorization: Bearer <token>
JWT 的认证流程图
JWT 的优缺点
JWT 的优点
- 不需要在服务端保存会话信息(RESTful API 的原则之一就是无状态), 所以易于应用的扩展, 即信息不保存在服务端, 不会存在 Session 扩展不方便的情况
- JWT 中的 Payload 负载可以存储常用信息, 用于信息交换, 有效地使用 JWT, 可以降低服务端查询数据库的次数
JWT 的缺点
- 加密问题: JWT 默认是不加密, 但也是可以加密的。生成原始 Token 以后, 可以用密钥再加密一次
- 到期问题: 由于服务器不保存 Session 状态, 因此无法在使用过程中废止某个 Token, 或者更改 Token 的权限。也就是说, 一旦 JWT 签发了, 在到期之前就会始终有效, 除非服务器部署额外的逻辑
5. 其他
单点登录(Single Sign On)
- 在同域下的客户端/服务端认证系统中, 通过客户端携带凭证, 可以维持一段时间内的登录状态
- 但随着企业的发展, 一个大型系统里可能包含 n 多子系统, 用户在操作不同的系统时, 需要多次登录, 很麻烦, 那么单点登录(SSO)就可以很好的解决这个问题的, 在多个应用系统中, 只需要登录一次, 就可以访问其他相互信任的应用系统
OAuth 2.0
- OAuth 是一个开放标准, 允许用户授权第三方网站 (CSDN、思否等) 访问他们存储在另外的服务提供者上的信息, 而不需要将用户名和密码提供给第三方网站
- 常见的提供 OAuth 认证服务的厂商: 支付宝、QQ、微信、微博
- 简单说, OAuth 就是一种授权机制。数据的所有者告诉系统, 同意授权第三方应用进入系统, 获取这些数据。系统从而产生一个短期的进入令牌(Token), 用来代替密码, 供第三方应用使用
- 令牌(Token)与密码(Password)的作用是一样的, 都可以进入系统, 但是有三点差异
- 令牌是短期的, 到期会自动失效: 用户自己无法修改。密码一般长期有效, 用户不修改, 就不会发生变化
- 令牌可以被数据所有者撤销, 会立即失效
- 令牌有权限范围(scope): 对于网络服务来说, 只读令牌就比读写令牌更安全。密码一般是完 整权限
联合登录和信任登录
- 联合登录 指同时包含多种凭证校验的登录服务, 同时, 也可以理解为使用第三方凭证进行校验的登录服务
- 信任登录 是指所有不需要用户主动参与的登录, 例如建立在私有设备与用户之间的绑定关系, 凭证就是私有设备的信息, 此时不需要用户再提供额外的凭证。信任登录又指用第三方比较成熟的用户库来校验凭证, 并登录当前访问的网站
唯一登录
唯一登录, 指的是禁止多人同时登录同一账号, 后者的登录行为, 会导致前者掉线
扫码登录
- 扫码登录通常见于移动端 APP 中, 很多 PC 端的网站都提供了扫码登录的功能, 无需在网页上输入任何账号和密码, 只需要让移动端 APP (如微信、淘宝、QQ等等) 中已登录用户主动扫描⼆维码, 再确认登录, 以使 PC 端的同款应用得以快速登录的方式就是扫码登录
一键登录(适用于原生APP)
- 短信验证码的作用就是证明当前操作页面的用户与输入手机号的用户为相同的人, 那么实际上只要我们能够获取到当前手机使用的手机卡号, 直接使用这个号码进行登录, 不需要额外的操作, 这就是一键登录。