身份认证与访问控制:多因素认证(MFA)实现、OAuth2.0与JWT令牌管理、基于角色的访问控制(RBAC)、会话管理最佳实践
大家好,我是你们这堂课的老朋友。今天咱们聊一个老生常谈,但又极其容易翻车的话题——身份认证与访问控制。
说实话,我在安全这行干了十几年,见过太多系统被攻破的案例。十次里有八次,问题都出在认证和授权上。你想想看,一个交易系统,如果连谁在操作都搞不清楚,那还谈什么安全?
所以这一章,我会把多因素认证、OAuth2.0、JWT、RBAC 和会话管理这几个核心点,掰开了揉碎了讲清楚。嗯,咱们开始吧。
一、多因素认证(MFA)——别只靠一个密码
先问个问题:你的系统还在只用密码登录吗?
我个人习惯,只要涉及资金交易,MFA 是必须上的。为什么?因为密码太容易被攻破了。撞库、钓鱼、暴力破解……手段多得很。
MFA 的核心逻辑很简单:证明你是你,至少用两种不同的方式。
- 你知道的:密码、PIN码
- 你拥有的:手机、硬件令牌、U盾
- 你本身的:指纹、人脸、虹膜
重要提醒:MFA 不是简单的“密码 + 短信验证码”就完事了。短信验证码有被拦截的风险(比如 SIM 卡劫持)。我个人更推荐 TOTP(基于时间的一次性密码)或硬件密钥。
我在项目中遇到过一件事:一个客户坚持只用短信验证码做第二因素,结果被攻击者通过社会工程学手段补办了 SIM 卡,所有验证码都被截获了。那次教训挺深刻的。
实战建议:对于高价值交易,建议强制使用硬件令牌(如 YubiKey)或生物识别。短信验证码可以作为低风险操作的备选。
二、OAuth2.0 与 JWT 令牌管理——别让令牌满天飞
说到 OAuth2.0,很多人第一反应就是“授权框架”。没错,但它不是万能的。我见过不少团队把 OAuth2.0 当成了认证协议在用,结果搞得一团糟。
OAuth2.0 的核心是授权,不是认证。它解决的是“第三方应用能不能访问我的资源”这个问题。而 JWT(JSON Web Token)则是 OAuth2.0 中常用的一种令牌格式。
JWT 的结构
JWT 由三部分组成:Header、Payload、Signature。用 Base64 编码后,用点号连接。
// 一个典型的 JWT 示例
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
注意:JWT 的 Payload 只是 Base64 编码,不是加密!敏感信息(如密码、信用卡号)绝对不能放在里面。我曾经审计过一个项目,他们把用户手机号直接放进了 JWT 的 Payload 里……嗯,后果可想而知。
OAuth2.0 的四种授权模式
| 模式 | 适用场景 | 安全级别 |
|---|---|---|
| 授权码模式 | 有后端的 Web 应用 | 高 |
| 隐式模式 | 纯前端应用(已不推荐) | 低 |
| 密码模式 | 高度信任的客户端 | 中 |
| 客户端凭证模式 | 服务间通信 | 高 |
我个人习惯,在交易系统中,授权码模式 + PKCE 是首选。PKCE 能有效防止授权码被拦截后的重放攻击。
避坑指南:我曾经见过一个团队,为了省事,在移动端用了隐式模式。结果 access_token 直接暴露在 URL 中,被日志系统记录了下来。后来被内部安全扫描发现,紧急整改了一周。
三、基于角色的访问控制(RBAC)——权限不是大锅饭
RBAC 听起来简单,但落地时很容易出问题。说白了,就是“什么人能干什么事”。
但很多团队把 RBAC 做成了“大锅饭”——要么给所有人管理员权限,要么权限粒度粗得离谱。
我建议这样设计:
- 角色:交易员、审核员、管理员、审计员
- 权限:创建订单、审核订单、撤销订单、查看报表
- 角色-权限映射:一个角色可以拥有多个权限
// 一个简单的 RBAC 数据模型示例
{
"roles": {
"trader": ["create_order", "view_own_orders"],
"auditor": ["view_all_orders", "view_reports"],
"admin": ["create_order", "view_all_orders", "cancel_order", "manage_users"]
}
}
核心原则:最小权限原则。给每个角色只分配完成工作所必需的最小权限集。不要图省事给“超级管理员”。
我在项目中遇到过一件事:一个交易系统,所有操作员都用的同一个角色,权限一模一样。结果一个实习生误操作,批量撤销了当天的所有订单。嗯,那天晚上整个团队都在加班恢复数据。
四、会话管理最佳实践——别让会话成为后门
会话管理,说白了就是“用户登录后,系统怎么记住他”。但这里面的坑,比你想的要多。
会话 ID 的生成
千万别用自增 ID、时间戳、或者简单的 MD5。攻击者很容易预测或伪造。
我建议使用加密安全的随机数生成器,长度至少 128 位。
// 安全的会话 ID 生成示例(伪代码)
session_id = crypto.randomBytes(32).toString('hex')
会话的存储
服务端会话建议用 Redis 或 Memcached,设置合理的过期时间。客户端会话(如 JWT)要设置较短的过期时间,并配合刷新令牌。
| 存储方式 | 优点 | 缺点 |
|---|---|---|
| 服务端存储(Redis) | 可主动失效、可审计 | 增加服务端开销 |
| 客户端存储(JWT) | 无状态、扩展性好 | 无法主动失效 |
注意:JWT 一旦签发,在过期之前是无法撤销的。所以对于交易系统,我建议 JWT 的过期时间不要超过 15 分钟,并配合刷新令牌使用。
会话的失效
用户登出、修改密码、账号被锁定等场景,必须立即失效会话。
对于服务端存储的会话,直接删除 Redis 中的 key 即可。对于 JWT,可以维护一个黑名单(但会增加复杂度),或者使用短过期时间。
避坑指南:我曾经见过一个系统,用户修改密码后,旧的 JWT 仍然有效。攻击者只要在修改密码前拿到了令牌,就能继续操作。后来我们加了一个“密码版本号”字段,每次修改密码后版本号递增,JWT 中携带版本号,服务端校验时比对,不匹配则拒绝。
知识体系总览
下面这张图,是我自己梳理的本章知识体系。你可以把它当作一个思维导图来看。
好了,这一章的内容就到这里。身份认证与访问控制,说白了就是“你是谁”和“你能干什么”这两个问题。把这两个问题搞清楚了,你的系统安全就有了七成的保障。
记住,安全不是一锤子买卖,而是一个持续迭代的过程。希望今天的分享,能帮你少踩一些坑。