认证与授权速查表
本文档提供认证与授权常用协议、代码片段及安全配置的快速参考。
认证协议选择指南
| 协议 | 适用场景 | 核心特点 |
|---|---|---|
| Session-Cookie | 单体 Web 应用、管理后台 | 服务端存储状态、安全性高、实现简单 |
| JWT | 微服务、移动端、无状态 API | 客户端存状态、易扩展、需处理令牌撤销 |
| OAuth 2.1 | 第三方登录、API 授权 | 行业标准、必须使用 PKCE、支持多种客户端 |
| OIDC | 身份识别、SSO、统一身份 | 基于 OAuth 2.0、标准化用户信息(ID Token) |
| SAML 2.0 | 企业传统应用、HR/ERP | XML 断言、强审计能力、配置复杂 |
JWT 快速参考
结构
header.payload.signature
Header 示例
{
"alg": "RS256",
"typ": "JWT"
}
常用声明 (Claims)
| 声明 | 含义 | 说明 |
|---|---|---|
iss | Issuer | 签发者 |
sub | Subject | 主题(通常是用户 ID) |
aud | Audience | 接收方 |
exp | Expiration | 过期时间(Unix 时间戳) |
iat | Issued At | 签发时间 |
nbf | Not Before | 生效时间 |
jti | JWT ID | 唯一标识 |
签名算法
| 算法 | 类型 | 适用场景 |
|---|---|---|
| HS256 | 对称(HMAC) | 单服务、简单场景 |
| RS256 | 非对称(RSA) | 微服务、推荐生产使用 |
| ES256 | 非对称(ECDSA) | 高性能场景 |
Node.js 代码
const jwt = require('jsonwebtoken');
// 签发
const token = jwt.sign(
{ sub: 'user_123', role: 'admin' },
process.env.JWT_SECRET,
{ expiresIn: '15m', algorithm: 'RS256' }
);
// 验证
try {
const payload = jwt.verify(token, publicKey, { algorithms: ['RS256'] });
} catch (err) {
// TokenExpiredError | JsonWebTokenError | NotBeforeError
}
Python 代码
import jwt
# 签发
token = jwt.encode(
{'sub': 'user_123', 'role': 'admin'},
SECRET_KEY,
algorithm='HS256',
headers={'exp': datetime.utcnow() + timedelta(minutes=15)}
)
# 验证
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
except jwt.ExpiredSignatureError:
pass
except jwt.InvalidTokenError:
pass
安全检查清单
- 明确指定允许的算法(algorithms 参数)
- 验证
exp声明 - 验证
iss签发者 - 验证
aud受众 - 使用足够长度的密钥(≥256 位)
- 敏感数据不放入载荷
- Access Token 有效期不超过 1 小时
- 实现 Refresh Token 机制
OAuth 2.1 快速参考
授权码模式流程
1. GET /authorize?response_type=code&client_id=ID&redirect_uri=URI&scope=openid&state=xyz&code_challenge=HASH&code_challenge_method=S256
2. 用户授权后重定向:redirect_uri?code=AUTH_CODE&state=xyz
3. POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=CODE&redirect_uri=URI&client_id=ID&code_verifier=ORIGINAL
常用 Scope
| Scope | 含义 |
|---|---|
openid | OIDC 身份认证 |
profile | 用户基本信息 |
email | 用户邮箱 |
offline_access | 获取 Refresh Token |
PKCE 代码
// 生成 code_verifier
const codeVerifier = crypto.randomBytes(32).toString('base64url');
// 计算 code_challenge
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
State 参数验证
import secrets
# 发起授权请求
state = secrets.token_urlsafe(32)
session['oauth_state'] = state
# 验证回调
if request.args.get('state') != session.pop('oauth_state'):
raise SecurityError('Invalid state')
Cookie 安全配置
推荐配置
Set-Cookie: sessionId=abc123;
HttpOnly;
Secure;
SameSite=Lax;
Path=/;
Max-Age=3600;
Domain=example.com
属性说明
| 属性 | 说明 |
|---|---|
HttpOnly | 禁止 JavaScript 访问,防 XSS |
Secure | 仅 HTTPS 传输 |
SameSite=Strict | 仅同站请求携带 |
SameSite=Lax | 导航到目标站点的 GET 请求携带(推荐) |
SameSite=None | 允许跨站(必须配合 Secure) |
密码哈希
推荐算法
| 算法 | 特点 | 推荐度 |
|---|---|---|
| Argon2id | 抗 GPU 攻击、内存硬化 | ★★★★★ |
| bcrypt | 主流选择、计算成本可调 | ★★★★☆ |
| scrypt | 内存硬化 | ★★★★☆ |
| PBKDF2 | 兼容性好、可定制迭代次数 | ★★★☆☆ |
禁止使用
- MD5、SHA-1、SHA-256 等快速哈希
- 明文存储
Argon2 示例
import argon2
ph = argon2.PasswordHasher()
# 哈希
hashed = ph.hash("password123")
# 验证
try:
ph.verify(hashed, "password123")
except argon2.exceptions.VerifyMismatchError:
print("密码错误")
bcrypt 示例
const bcrypt = require('bcrypt');
// 哈希(cost factor: 12)
const hash = await bcrypt.hash('password123', 12);
// 验证
const match = await bcrypt.compare('password123', hash);
HTTP 安全头
完整配置
# 防止点击劫持
add_header X-Frame-Options "SAMEORIGIN" always;
# 强制 HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# 内容安全策略
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;" always;
# 禁用 MIME 嗅探
add_header X-Content-Type-Options "nosniff" always;
# XSS 保护
add_header X-XSS-Protection "1; mode=block" always;
# Referrer 策略
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# 权限策略
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
权限模型对比
| 模型 | 核心概念 | 适用场景 |
|---|---|---|
| RBAC | 用户 → 角色 → 权限 | 组织结构清晰、权限稳定 |
| ABAC | 属性 + 策略 → 决策 | 动态决策、零信任架构 |
| ReBAC | 实体关系 → 权限 | 社交网络、协作工具 |
| ACL | 资源 → 用户列表 | 简单场景、文件系统 |
RBAC 数据库设计
-- 核心表
users(id, username, email)
roles(id, name, description)
permissions(id, resource, action)
user_roles(user_id, role_id)
role_permissions(role_id, permission_id)
RBAC 权限检查
// 检查权限
async function hasPermission(userId, resource, action) {
const query = `
SELECT 1 FROM permissions p
JOIN role_permissions rp ON p.id = rp.permission_id
JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = ? AND p.resource = ? AND p.action = ?
`;
return (await db.query(query, [userId, resource, action])).length > 0;
}
MFA 方式对比
| 方式 | 安全性 | 便捷性 | 成本 | 推荐 |
|---|---|---|---|---|
| TOTP | 高 | 中 | 无 | ★★★★★ |
| Passkeys | 最高 | 高 | 无 | ★★★★★ |
| 短信验证码 | 中 | 高 | 有 | ★★★☆☆ |
| 邮箱验证码 | 中 | 高 | 低 | ★★★☆☆ |
| 硬件密钥 | 最高 | 中 | 有 | ★★★★☆ |
TOTP 生成
import pyotp
# 生成密钥
secret = pyotp.random_base32()
# 生成 otpauth URL
uri = pyotp.totp.TOTP(secret).provisioning_uri(
name='[email protected]',
issuer_name='MyApp'
)
# 验证
totp = pyotp.TOTP(secret)
is_valid = totp.verify(user_input)
密码安全快速参考
密码哈希算法选择
| 算法 | 内存硬度 | GPU 抵抗 | 推荐度 |
|---|---|---|---|
| Argon2id | 高 | 强 | ★★★★★ |
| bcrypt | 中 | 中 | ★★★★☆ |
| scrypt | 高 | 强 | ★★★★☆ |
| PBKDF2 | 低 | 弱 | ★★★☆☆ |
| SHA/MD5 | 无 | 无 | ✗ 禁止 |
密码策略(NIST SP 800-63B)
| 场景 | 最小长度 | 推荐最大长度 |
|---|---|---|
| 启用 MFA | 8 字符 | 至少 64 字符 |
| 未启用 MFA | 15 字符 | 至少 64 字符 |
密码安全检查清单
- 使用 Argon2id 或 bcrypt 存储密码
- 禁止明文存储和通用哈希(SHA/MD5)
- 检查密码是否在已知泄露数据库中
- 不强制要求复杂度规则(大小写、数字、符号)
- 允许所有可打印字符(包括空格和 Unicode)
- 使用密码强度评估工具(如 zxcvbn)
- 不强制定期更改密码(除非泄露)
- 登录成功后重新生成会话 ID
密码重置安全要点
- 令牌足够长(≥32 字节),使用加密安全随机数
- 令牌有效期短(15-30 分钟)
- 存储令牌的哈希值,不存原文
- 使用后立即失效
- 防止用户枚举(统一响应)
- 重置后使所有现有会话失效
常见安全攻击防御
| 攻击类型 | 核心防御 |
|---|---|
| 暴力破解 | 账户锁定、速率限制、CAPTCHA、MFA |
| 撞库攻击 | 泄露检测、IP 信誉、MFA |
| 密码喷洒 | 全局速率限制、IP 限制 |
| 会话劫持 | 安全 Cookie、会话绑定、HTTPS |
| 会话固定 | 登录后重新生成会话 ID |
| CSRF | SameSite Cookie + CSRF Token |
| 重放攻击 | Nonce、时间戳验证 |
| JWT 攻击 | 算法白名单、密钥分离 |
常见安全漏洞检查
| 漏洞 | 检查点 | 防御方案 |
|---|---|---|
| 会话劫持 | Cookie 是否设了 HttpOnly? | 启用 HttpOnly |
| 会话固定 | 登录后是否更换 Session ID? | 登录后 regenerate() |
| CSRF | POST 请求是否验证 Token? | SameSite=Lax + CSRF Token |
| XSS | 是否转义用户输入? | CSP + 输出编码 |
| JWT 注入 | 是否信任 alg: none? | 硬编码只接受 RS256/HS256 |
| 密钥泄露 | 密钥是否硬编码? | 环境变量或密钥管理服务 |
| SQL 注入 | 是否拼接 SQL? | 使用参数化查询 |
| 弱密码 | 是否有密码强度要求? | 强制密码策略 |
错误码速查
| HTTP 状态码 | 含义 |
|---|---|
| 401 Unauthorized | 未认证 |
| 403 Forbidden | 已认证但无权限 |
| 400 Bad Request | 请求格式错误 |
| 409 Conflict | 资源冲突(如用户名已存在) |
常用身份提供商
| 提供商 | 协议支持 | 适用场景 |
|---|---|---|
| Auth0 | OAuth 2.0, OIDC, SAML | 企业应用、CIAM |
| Okta | OAuth 2.0, OIDC, SAML | 企业 SSO |
| Azure AD | OAuth 2.0, OIDC, SAML | Microsoft 生态 |
| Keycloak | OAuth 2.0, OIDC, SAML | 开源自托管 |
| Firebase Auth | OAuth 2.0, OIDC | 移动应用、快速开发 |