架构安全
架构安全解决三个核心问题:「你是谁」(认证)、「你能做什么」(授权)、「传输过程安全」(加密)。微服务架构下,服务间调用同样需要处理认证和授权问题。
提示
认证、授权、加密、凭证管理的安全体系
适用场景
- 用户登录系统:JWT/Session 实现无状态或有状态认证
- 第三方登录集成:OAuth 2.0 授权码模式对接微信、GitHub 等
- 微服务间调用:服务网格 mTLS 双向认证
- API 网关鉴权:统一 Token 验证和权限校验
- 敏感数据保护:密码加盐 Hash、API 密钥管理
- 合规要求:等保、GDPR 等安全合规场景
认证 vs 授权
| 维度 | 认证(AuthN) | 授权(AuthZ) |
|---|---|---|
| 问题 | 你是谁? | 你能做什么? |
| 时机 | 登录时 | 访问资源时 |
| 凭证 | 用户名/密码、Token、证书 | 角色、权限列表 |
认证先于授权,确认身份后再判断权限。
JWT
JWT 由三部分组成:Header.Payload.Signature,通过 Base64 URL 编码。
| 部分 | 内容 | 说明 |
|---|---|---|
| Header | {"alg":"HS256","typ":"JWT"} | 签名算法和类型 |
| Payload | {"sub":"123","exp":1698000000} | 声明(用户信息、过期时间) |
| Signature | HMAC-SHA256 签名 | 防篡改 |
Payload 是 Base64 编码而非加密,不要存放敏感信息。TTL 建议短(如 15 分钟),配合 Refresh Token 机制。
JWT vs Session
| 维度 | Session | JWT |
|---|---|---|
| 存储 | 服务端 | 客户端 |
| 水平扩展 | 需要共享 Session(Redis) | 无状态,天然支持 |
| 注销 | 直接删除 | 需 Redis 黑名单或短过期 |
OAuth 2.0
OAuth 2.0 是开放授权标准,允许第三方应用获取用户授权而无须获取用户密码。
四种授权模式
| 模式 | 适用场景 | 安全性 |
|---|---|---|
| 授权码模式 | 有后端服务的 Web 应用 | 最高(推荐) |
| 简化模式(已废弃) | 纯前端 SPA | 低 |
| 密码模式 | 高度信任的客户端 | 中 |
| 客户端凭证 | 服务间调用(无用户参与) | 高 |
授权码流程
授权码中转防止 token 泄露给浏览器。
访问控制
访问控制决定谁能访问什么资源,是授权的具体执行机制。
RBAC
RBAC 简单直观,适合组织结构明确、权限稳定的场景。缺点是角色爆炸和灵活性不足。
服务治理 中网关的认证鉴权可基于 RBAC/ABAC 实现。
ABAC
ABAC(基于属性的访问控制)根据用户属性、资源属性、环境属性(时间、位置)动态决定权限,灵活度高,但策略计算复杂。
@PreAuthorize("@permissionService.canEdit(authentication, #resourceId)")
public Document updateDocument(@PathVariable Long resourceId) {
return documentService.update(resourceId, dto);
}HTTPS / TLS
TLS 握手核心:非对称加密(RSA/ECC)交换密钥,对称加密(AES)传输数据。
TLS 1.3 简化了握手流程,减少了往返次数。
凭证安全
密码存储
// 错误:MD5 可被彩虹表破解
user.setPassword(MD5("123456"));
// 正确:BCrypt 加盐 Hash
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
user.setPassword(encoder.encode("123456"));
encoder.matches("123456", storedHash); // 验证BCrypt 内置随机盐,每次 Hash 结果不同,计算成本可调。
API 密钥原则
| 原则 | 说明 |
|---|---|
| 不硬编码 | 密钥不进代码仓库 |
| 环境变量 | 通过 ${API_KEY} 注入 |
| 密钥管理服务 | AWS Secrets Manager / 阿里云 KMS |
常见漏洞
| 漏洞 | 原因 | 防御 |
|---|---|---|
| SQL 注入 | 拼接 SQL | PreparedStatement / MyBatis 参数化 |
| XSS | 未过滤用户输入 | 输出转义、CSP |
| CSRF | 跨站请求伪造 | CSRF Token、SameSite Cookie |
| JWT 伪造 | alg 设为 none | 服务端强制验证算法 |
| 越权访问(IDOR/BOLA) | 只校验了登录,没校验资源归属 | 每次访问都校验主体对资源的权限,禁止仅凭 URL 中的 id 直接返回 |
越权是实际业务中最常见的漏洞:用户 A 登录后通过修改请求中的 id 访问用户 B 的数据。防御要点:对象级授权校验不能只做前端/网关,必须在服务端资源访问处执行——查询前先确认 resource.ownerId == currentUser.id 或角色有权限。
SSO 单点登录
多系统场景下用户只登录一次,即可访问所有互信系统。常见方案:
| 方案 | 原理 | 适用 |
|---|---|---|
| 共享 Session | 各系统共享 Redis Session,Cookie 域名统一 | 同域系统 |
| CAS(中心认证服务) | 统一认证中心签发 TGT/ST 票据,各系统验证票据 | 传统企业系统 |
| OAuth2/OIDC | 认证服务器颁发 ID Token,各系统校验签名 | 现代微服务 |
OIDC 流程简化:
用户 → 系统A → 302 → 认证中心(登录)→ 签发 ID Token
系统A 校验 Token → 放行;用户访问系统B → 302 → 认证中心(已登录,直接发 Token)→ 放行防重放攻击
重放攻击:攻击者截获合法请求(如支付请求)后原样重发。防御手段(通常组合使用):
| 手段 | 原理 | 缺点 |
|---|---|---|
| 时间戳 | 请求携带时间戳,超过窗口(如 5 分钟)拒绝 | 时钟不同步/网络延迟会误伤 |
| Nonce(随机数) | 请求携带唯一随机数,服务端记录已用 Nonce | 需存储已用 Nonce,占用内存 |
| 签名机制 | 请求体 + 时间戳 + Nonce 一起签名 | 防篡改但无法防重发 |
| 幂等 Token | 见 远程服务调用,业务层去重 | 从业务上消除重复影响 |
典型 API 防重放:timestamp + nonce + sign(参数+timestamp+nonce+密钥),服务端校验时间窗口内的 nonce 唯一性。
常见问题
Q: JWT 和 Session 怎么选?
A: 单体应用用 Session(简单、注销方便);微服务/跨域场景用 JWT(无状态、天然支持分布式)。JWT 必须配合短过期时间 + Refresh Token。
Q: OAuth 2.0 四种模式怎么选?
A: 有后端的 Web 应用用授权码模式(最安全);纯前端 SPA 用 PKCE 模式(授权码的改进版);服务间调用用客户端凭证模式;密码模式仅用于高度信任的第一方应用。
Q: 密码存储为什么不能用 MD5?
A: MD5 速度快、无盐,可被彩虹表秒破。BCrypt 内置随机盐、计算成本可调(默认 10 轮),暴力破解成本极高。
Q: HTTPS 能防止中间人攻击吗?
A: 能,但前提是正确配置:1) 使用 TLS 1.2+;2) 禁用弱加密套件;3) 验证证书链;4) 开启 HSTS。自签名证书无法防止中间人攻击。
Q: 微服务间如何保证调用安全?
A: 1) 服务网格 mTLS 双向认证;2) API 网关统一鉴权;3) JWT 透传用户身份;4) 最小权限原则配置服务账号。