那些鉴权相关的知识
# 那些鉴权相关的知识
# 认证、授权、凭证
# 什么是认证(Authentication)
- 通俗地讲就是验证当前用户的身份
- 互联网中的认证:
- 用户名密码登录
- 邮箱发送登录链接
- 手机号接收验证码
- 只要你能收到邮箱/验证码,就默认你是账号的主人
# 什么是授权(Authorization)
用户授予第三方应用访问该用户某些资源的权限
你在安装手机应用的时候,APP 会询问是否允许授予权限(访问相册、地理位置等权限)
你在访问微信小程序时,当登录时,小程序会询问是否允许授予权限(获取昵称、头像、地区、性别等个人信息)
常见授权方式:
- Cookie。
- Session。
- Token。
- OAuth。
# 什么是凭证(Credentials)
- 凭证用于认证后,可生成会话或令牌,用于后续授权。
- 凭证是用户或系统用来证明自己身份的信息。是在身份验证成功后,用来表明身份和授权的标识。
- Session ID:通过用户名和密码登录后生成的。
- Token 或 JWT:验证用户名和密码后发放的令牌。
- 是一种 **媒介(证书)**用来标记访问者的身份
- 在战国时期,商鞅变法,发明了照身帖。照身帖由官府发放,是一块打磨光滑细密的竹板,上面刻有持有人的头像和籍贯信息。国人必须持有,如若没有就被认为是黑户,或者间谍之类的。
- 在现实生活中,每个人都会有一张专属的居民身份证,是用于证明持有人身份的一种法定证件。通过身份证,我们可以办理手机卡/银行卡/个人贷款/交通出行等等,这就是认证的凭证。
- 在互联网应用中,一般网站(如掘金)会有两种模式,游客模式和登录模式。游客模式下,可以正常浏览网站上面的文章,一旦想要点赞/收藏/分享文章,就需要登录或者注册账号。当用户登录成功后,服务器会给该用户使用的浏览器颁发一个令牌(token),这个令牌用来表明你的身份,每次浏览器发送请求时会带上这个令牌,就可以使用游客模式下无法使用的功能。
# 鉴权机制
# 一、什么是 Cookie
HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):
- 每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。
- 所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。
- 而这个状态需要通过 cookie 或者 session 去实现。
Cookie 是存储在浏览器中的小型文本文件,由服务器发送并存储在用户的设备上。(即存储在客户端)
保存在本地的一小块数据
用于在客户端和服务器之间共享数据。
特点:
- 每次请求时会自动发送给服务器。
- 可以设置过期时间。
- 支持跨页面共享。
- cookie 是不可跨域的: 每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)
常见用途:
- 保存用户登录状态。
- 存储偏好设置(如语言、主题)。
- 跟踪用户行为(如广告投放)。
cookie 重要的属性:
属性 说明 name=value 键值对,设置 Cookie 的名称及相对应的值,都必须是字符串类型 - 如果值为 Unicode 字符,需要为字符编码。 - 如果值为二进制数据,则需要使用 BASE64 编码。 domain 指定 cookie 所属域名,默认是当前域名 path 指定 cookie 在哪个路径(路由)下生效,默认是 '/'。 如果设置为 /abc
,则只有/abc
下的路由可以访问到该 cookie,如:/abc/read
。maxAge cookie 失效的时间,单位秒。(1)如果为整数,则该 cookie 在 maxAge 秒后失效。(2)如果为负数,该 cookie 为临时 cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该 cookie 。(3)如果为 0,表示删除该 cookie 。 默认为 -1。比 expires 好用。 expires 过期时间,在设置的某个时间点后该 cookie 就会失效。一般浏览器的 cookie 都是默认储存的,当关闭浏览器结束这个会话的时候,这个 cookie 也就会被删除 secure 该 cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。 - 默认为 false。 - 当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。 httpOnly 如果给某个 cookie 设置了 httpOnly 属性,则无法通过 JS 脚本 读取到该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是在一定程度上可以防止 XSS 攻击,不是绝对的安全
# 二、什么是 Session
SessionID 是连接 Cookie 和 Session 的一道桥梁,大部分系统也是根据此原理来验证用户登录状态。
- Session 是另一种记录服务器和客户端会话状态的机制,用于记录用户的交互状态。
- 用户首次访问时,服务器创建一个 Session 对象,并生成一个唯一的 Session ID 返回给客户端(浏览器)。
- Session ID 通常通过 Cookie 或 URL 参数传递到客户端。
- session 是基于 cookie 实现的,session 存储在服务器端,SessionID 会被存储到客户端的 cookie 中
- 第二次请求时,携带 cookie 中的 SessionID,便于服务器判断 SessionID 属于哪个用户,并执行后续操作(为了进行会话跟踪 -- 知道是谁在访问我)
- 特点:
- 数据存储在服务器端,更安全。
- 通常与用户的会话周期绑定。
- 对服务器资源有一定消耗。
- 常见用途:
- 记录用户登录状态。
- 存储临时数据(购物车、浏览记录)。
验证流程:
# Cookie 和 Session 的区别
属性 | Cookie | Session |
---|---|---|
存储位置 | 客户端 | 服务器 |
安全性 | 较低,数据容易被篡改 | 较高,数据存储在服务器端 |
存取值的类型不同 | 只支持存字符串数据 | 可以存任意数据类型 |
生命周期 | 可设置过期时间,支持持久化 | 会话结束或超时后失效 |
存储容量 | 单个 Cookie 保存的数据不能超过 4KB | 取决于服务器资源 |
# 三、什么是 Token(令牌)
# Acesss Token
- Acesss Token 是访问受保护资源(资源接口 API)的凭证。
- 由服务器生成并返回给客户端。
- 客户端在后续请求中携带 Token,服务器验证后允许访问。
- 简单 token 的组成:
uid
(用户唯一的身份标识)、time
(当前时间的时间戳)、sign
(签名,使用某种哈希算法对uid
和time
等信息进行处理,生成固定长度的字符串。这个签名可以防止 token 被篡改,保证其安全性) - 特点:
- 通常是字符串,包含用户信息和签名。
- 无状态:服务器不需要存储 Token。
- 常见用途:
- API 认证。
- 分布式系统的鉴权。
身份验证流程:
- 客户端使用用户名跟密码请求登录
- 服务端收到请求,去验证用户名与密码
- 验证成功后,服务端会签发一个 token 并把这个 token 发送给客户端
- 客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里
- 客户端每一次向服务端请求资源的时候都需要带着服务端签发的 token,把 token 放到 HTTP 的 Header 里
- 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据
- 基于 token 的用户认证是一种服务端无状态的认证方式
- 服务端不用存放 token 数据。
- 用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库。
- token 完全由应用管理,所以它可以避开同源策略
# Refresh Token
- 另外一种 token —— refresh token
- refresh token 是专用于刷新 access token 的 token
- 如果没有 refresh token,也可以刷新 access token,但每次刷新都要用户输入登录用户名与密码,会很麻烦。
- 有了 refresh token,可以减少这个麻烦,客户端直接用 refresh token 去更新 access token,无需用户进行额外的操作。
- Access Token 的有效期比较短,当 Acesss Token 由于过期而失效时,使用 Refresh Token 就可以获取到新的 Token,如果 Refresh Token 也失效了,用户就只能重新登录了。
- Refresh Token 及过期时间是存储在服务器的数据库中,只有在申请新的 Acesss Token 时才会验证,不会对业务接口响应时间造成影响,也不需要向 Session 一样一直保持在内存中以应对大量的请求。
验证流程:
# Token 和 Session 的区别
- 状态性不同
- Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。
- 而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。
- Session 和 Token 并不矛盾
- token,每一个请求都有签名还能防止监听以及重放攻击,
- 而 Session 就必须依赖链路层来保障通讯安全了。
- 如果你需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态。
- 简单来说:
- 如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token。
- 如果永远只是自己的网站,自己的 App,用什么就无所谓了。
属性 | Token | Session |
---|---|---|
存储位置 | 客户端(通常在 LocalStorage 或 Cookie 中) | 服务器端 |
状态性 | 无状态 | 有状态 |
扩展性 | 适合分布式系统 | 适合单服务器系统 |
安全性 | 存储在客户端,需防止泄露 | 存储在服务器,更安全 |
# 四、什么是 JWT
- JWT(JSON Web Token)是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准,用于在客户端与服务器之间安全地传递信息。
- 信息以 JSON 格式存储,结构分为三部分:Header、Payload、Signature。
- 流行的跨域认证解决方案。
- 是一种认证授权机制。
- 结构:
- Header:元信息(类型和签名算法)。
- Payload:数据负载(用户信息、权限等)。
- Signature:签名,用于验证数据完整性。
- 特点:
- 自包含:JWT 包含了身份信息,无需额外查询数据库。
- 无状态:服务器不存储 JWT。
- 易于扩展,适合微服务架构。
- 使用场景:
- 用户认证。
- 单点登录(SSO)。
# Token 和 JWT 的区别
相同:
- 都是访问资源的令牌
- 都可以记录用户的信息
- 都是使服务端无状态化
- 都是只有验证成功后,客户端才能访问服务端上受保护的资源
区别:
- Token:服务端验证客户端发送过来的 Token 时,还需要查询数据库获取用户信息,然后验证 Token 是否有效。
- JWT: 将 Token 和 Payload 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。
属性 | Token | JWT |
---|---|---|
格式 | 自定义 | 标准格式(Header.Payload.Signature) |
状态性 | 无状态 | 无状态 |
信息存储 | 通常不包含用户信息 | 自包含用户信息 |
验证方式 | 自定义 | 基于签名验证 |
# 常见的前后端鉴权方式
- Cookie + Session
- 客户端使用 Cookie 存储 Session ID。
- 服务器通过 Session ID 识别用户身份。
- Token-based Authentication
- 客户端使用 Token 请求受保护资源。
- 服务器验证 Token 有效性。
- JWT Authentication
- 客户端携带 JWT,服务器通过签名验证。
- OAuth 2.0(开放授权)
- 第三方授权协议,适用于开放平台。
# 常见的加密算法
- 哈希算法
- MD5、SHA-1、SHA-256。
- 不可逆,加密后无法还原。
- 对称加密
- AES、DES。
- 加密和解密使用同一密钥。
- 非对称加密
- RSA、ECC。
- 使用公钥加密,私钥解密。
- 签名算法
- HMAC(基于哈希的消息认证码)。
- 用于验证消息完整性和身份。
哈希算法:
- 将数据重新打乱混合,重新创建一个哈希值
- 正像快速:原始数据可以快速计算出哈希值
- 逆向困难:通过哈希值基本不可能推导出原始数据
- 输入敏感:原始数据只要有一点变动,得到的哈希值差别很大
- 冲突避免:很难找到不同的原始数据得到相同的哈希值
# 常见问题
# 使用 Cookie 时需要考虑的问题
- 安全性:
- 设置
Secure
属性:如果为 true,则只有在 HTTPS 连接时,cookie 才能被发送。 - 设置
HttpOnly
属性:防止 JavaScript 访问 cookie,增加抵御 XSS 攻击的能力。 - 设置
SameSite
属性:防止 CSRF 攻击。可以设置为Strict
、Lax
或None
,确保 cookie 仅在同一站点请求时发送。
- 设置
- 存储大小限制:
- Cookie 的大小通常受限于 4KB,因此不适合存储大量数据。
- 跨域问题:
- 不同域之间的 cookie 默认无法共享。需要在服务器端进行跨域配置,或者使用
Access-Control-Allow-Credentials
和Access-Control-Allow-Origin
配置。
- 不同域之间的 cookie 默认无法共享。需要在服务器端进行跨域配置,或者使用
- 性能影响:
- 每次请求都会带上 cookie,可能会影响性能,特别是在数据量较大时。
# 使用 Session 时需要考虑的问题
- 存储位置:
- Session 数据通常存储在服务器端,但可以选择存储在内存、数据库或分布式缓存中。需要根据应用场景和访问量选择合适的存储方式。
- Session ID 管理:
- Session ID 通常存储在 cookie 中,需要确保 ID 的安全性。使用
HttpOnly
和Secure
来提高安全性。 - 避免暴露 Session ID,防止会话劫持。
- Session ID 通常存储在 cookie 中,需要确保 ID 的安全性。使用
- 会话过期与清除:
- 设置合适的会话超时和过期时间,避免泄露敏感信息。需要有机制定期清除过期的 Session 数据。
- 分布式系统:
- 在分布式系统中,Session 的共享和同步变得更加复杂。常用的解决方案包括使用 Redis 等分布式缓存来存储 Session 数据。
# 使用 Token 时需要考虑的问题
- 存储方式:
- Token 通常存储在客户端,常见存储方式包括 LocalStorage 和 SessionStorage。如果使用 cookie,需要确保设置适当的属性(如
HttpOnly
、Secure
)。
- Token 通常存储在客户端,常见存储方式包括 LocalStorage 和 SessionStorage。如果使用 cookie,需要确保设置适当的属性(如
- 过期机制:
- Token 一般有有效期,过期后需要重新获取。可以通过在 Token 中存储过期时间来管理。
- 刷新机制:
- 如果 Token 过期后,通常需要一个刷新 Token(Refresh Token)来重新获取新的访问 Token。
- Token 安全性:
- 确保 Token 不容易被窃取,尤其是在客户端存储时。如果使用 JWT,密钥管理非常重要。
- 跨域支持:
- Token 通常用于跨域认证,确保服务器的 CORS 配置支持跨域请求。
# 使用 JWT 时需要考虑的问题
- 签名和密钥管理:
- JWT 是通过签名进行验证的,确保签名算法(如 HMAC、RSA、ECDSA)和密钥的安全性。如果密钥泄露,攻击者可以伪造有效的 JWT。
- 过期时间设置:
- 在 JWT 中设置过期时间(
exp
),确保过期后不能再使用。合理的过期时间有助于减少 Token 被滥用的风险。
- 在 JWT 中设置过期时间(
- 防止重放攻击:
- 可以使用
jti
(JWT ID)字段来唯一标识每个 JWT,防止同一个 JWT 被多次使用。
- 可以使用
- Token 大小:
- JWT 中包含了用户信息和其他数据,可能导致 Token 比较大。在某些高频请求中,较大的 Token 会影响性能。
- 刷新机制:
- 使用 Refresh Token 机制,确保长时间会话保持有效,同时限制主 Token 的使用时长。
# 使用加密算法时需要考虑的问题
- 算法选择:
- 根据不同的应用需求选择适当的加密算法。常见的有对称加密(如 AES)和非对称加密(如 RSA)。对称加密速度较快,非对称加密更适合用于密钥交换和数字签名。
- 密钥管理:
- 密钥的管理非常关键。密钥应当存储在安全的地方(例如使用硬件安全模块 HSM 或密钥管理服务 KMS)。密钥泄露会使得加密数据完全暴露。
- 加密强度:
- 确保使用合适长度的密钥和强加密算法,避免使用已被破解或不再安全的算法(如 MD5、SHA1)。
- 性能问题:
- 加密和解密操作可能会增加性能负担,特别是在高并发环境下。因此,在设计时要权衡加密强度与性能需求。
- 避免重放攻击:
- 在使用加密进行认证时,增加时间戳、唯一标识符等机制,防止重放攻击。
- 加密模式:
- 在使用对称加密时,选择合适的加密模式(如 CBC、GCM)。不同模式有不同的安全性和性能特性,选择时要根据实际需求评估。
# 只要关闭浏览器 ,session 真的就消失了?
不一定。Session 的生命周期取决于它的存储方式和服务器的配置。通常有以下几种情况:
- 浏览器关闭后 Session 失效:
- 默认情况下,当 Session 存储在浏览器的内存中(如使用 Cookie 存储 Session ID),并且没有设置
Expires
或Max-Age
属性时,浏览器关闭后,存储的 Session 信息会被清除,这意味着 Session 会失效。 - 如果
Session
是存储在浏览器的sessionStorage
中,那么一旦浏览器关闭,sessionStorage
中的数据也会被清除。
- 默认情况下,当 Session 存储在浏览器的内存中(如使用 Cookie 存储 Session ID),并且没有设置
- Session 不会因为浏览器关闭而消失:
- 如果 Session 存储在 服务器端(大多数情况下是这样),那么即使用户关闭浏览器,Session 数据依然存在于服务器的存储(如内存、数据库、Redis 等)。这时,Session 依然有效,直到过期时间到达,或者显式地从服务器端销毁。
- 如果使用 持久化 Cookie(通过设置
Expires
或Max-Age
),则即使浏览器关闭,只要 Cookie 没过期,Session ID 依然会被保留,浏览器重新打开时,Session 可以继续有效。
- Session 超时:
- 即使 Session 没有在浏览器关闭时消失,也会受到会话超时(
session timeout
)的影响。服务器一般会设置一个会话超时时间(比如 30 分钟),当用户的 Session 在设定时间内没有任何请求,Session 会被自动销毁。
- 即使 Session 没有在浏览器关闭时消失,也会受到会话超时(
总结
- 如果 Session ID 存储在浏览器 Cookie 中,且没有设置持久化 Cookie,浏览器关闭后 Session 通常会丢失。
- 关闭浏览器后这个 session id 就消失了,由于客户端无法找到 Session ID,因此它无法再与服务器端的 Session 关联,从而 客户端认为 Session 丢失。
- 不是 Session 立即消失,直到 Session 过期或被清除(会话超时自动销毁),服务器端的 Session 数据才会消失。
- 如果服务器设置的 cookie 被保存在硬盘上,或者使用某种手段改写浏览器发出的 HTTP 请求头,把原来的 session id 发送给服务器,则再次打开浏览器仍然能够打开原来的 session。
- 如果 Session 存储在服务器端,浏览器关闭不会影响服务器上的 Session 存储。
- 如果设置了 Session 的过期时间,无论浏览器是否关闭,超时后 Session 会被销毁。
因此,是否消失取决于 Session 的存储位置和设置。
# 学习参考
上次更新: 2025/1/3 18:05:41