前端小食堂 | Day18 - 身份认证の八卦阵
🔐 今日秘术:JWT/OAuth2 攻防奥义
1. JWT 安全の六合阵法
// 🚫 危险操作:未验证签名
const decodeUnsafe = (token) => JSON.parse(atob(token.split('.')[1]));
// ✅ 安全姿势一:严格签名验证
import jwt from 'jsonwebtoken';
const payload = jwt.verify(token, secretKey, { algorithms: ['HS256'] });
// ✅ 安全姿势二:强制过期时间检查
if (payload.exp < Date.now() / 1000) throw new Error('令牌已过期');
// ✅ 安全姿势三:关键声明校验
if (payload.iss !== 'my-auth-server') throw new Error('非法签发方');
// 🔥 防御算法切换攻击
// 服务端配置拒绝"none"算法
jwt.verify(token, secretKey, { algorithms: ['HS256', 'RS256'] });
🔔 攻击类型识别:
- 令牌泄露:通过XSS/网络嗅探获取JWT
- 签名绕过:篡改Header中的
alg:none
- 密钥爆破:弱密钥被暴力破解
2. OAuth2 防御の四象结界
// 🚫 危险配置:开放重定向漏洞
const redirectUri = req.query.redirect_uri; // 未经验证直接使用
// ✅ 安全姿势一:白名单验证
const validUris = ['https://app.com/callback'];
if (!validUris.includes(redirectUri)) return 403;
// ✅ 安全姿势二:PKCE 增强
const codeVerifier = generateRandomString(64);
const codeChallenge = sha256(codeVerifier);
// 授权请求携带 challenge
redirectToAuthServer({
client_id,
code_challenge: codeChallenge,
code_challenge_method: 'S256'
});
// ✅ 安全姿势三:state参数防CSRF
const state = crypto.randomBytes(16).toString('hex');
storeInSession(state);
redirectToAuthServer({ state });
// 回调时校验state
if (req.query.state !== getFromSession()) throw new Error('非法请求');
❄️ 冷知识:现代安全机制
// 🛡️ Refresh Token 自动续期
let accessToken, refreshToken;
async function refreshTokens() {
try {
const newTokens = await axios.post('/refresh', { refreshToken });
accessToken = newTokens.access;
} catch (err) {
// 刷新失败则要求重新登录
logout();
}
}
// 🛡️ 浏览器安全存储
sessionStorage.setItem('token', token); // 标签页隔离
localStorage.setItem('refreshToken', encrypt(refreshToken)); // 加密存储
// 🛡️ 设备指纹绑定
const deviceId = generateFingerprint();
axios.post('/login', { ..., deviceId });
🌟 实验室安全工坊
实现安全令牌中间件
// JWT 安全校验中间件
const jwtAuth = (req, res, next) => {
try {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.sendStatus(401);
const payload = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'auth-server',
clockTolerance: 30 // 允许30秒时钟偏移
});
// 检查令牌是否被加入黑名单
if (redis.get(`jwt:${payload.jti}`)) return res.sendStatus(401);
req.user = payload;
next();
} catch (err) {
res.status(401).json({ error: '令牌无效' });
}
};
// 令牌吊销端点
app.post('/logout', (req, res) => {
const jti = req.user.jti; // JWT唯一标识
redis.set(`jwt:${jti}`, 'revoked', 'EX', 3600); // 吊销1小时
res.sendStatus(204);
});
明日秘境:《前端加密の奇门遁甲——HTTPS/数据加密实战》 🧪
(留言告诉我你遇到过的认证漏洞,本安全顾问为你定制防御结界!🔒)
🛎️ 本日避坑指南:
- JWT 十大危险操作
- 🚨 敏感数据存储于Payload
- 🚨 使用对称加密且密钥泄露
- 🚨 未设置合理的exp过期时间
- 🚨 接受任意签名算法
- 🚨 未处理令牌吊销场景
- OAuth2 安全红线
- 🚨 使用隐式授权(Implicit Flow)
- 🚨 允许任意redirect_uri
- 🚨 未校验response_type参数
- 🚨 客户端密钥明文存储
- 🚨 未使用PKCE增强移动端安全
- 安全头配置强化
# OAuth2 端点额外防护
add_header X-Content-Type-Options "nosniff" always;
add_header Cache-Control "no-store" always;
add_header Pragma "no-cache" always;
- 渗透测试工具
# JWT 攻击工具
https://github.com/ticarpi/jwt_tool
# OAuth2 测试套件
https://github.com/oauth2-proxy/oauth2-proxy
🔮 安全工具速递
工具 | 用途 |
---|---|
jwt.io | JWT 在线调试工具 |
OpenSSL | 密钥对生成与管理 |
Postman | OAuth2 流程测试 |
Keycloak | 开源认证服务器 |
OWASP ZAP | 自动化安全扫描 |