长短 Token 安全认证设计总结

长短 Token 安全认证设计总结

长短 Token 安全认证设计总结

1. 核心概念

| Token 类型 | 用途 | 生命周期 | 存储方式 | 安全要求 |

| ------------------------ | ------------ | -------------- | ------------------------ | ---------------- |

| 短 Token (Access Token) | 接口鉴权 | 短(如15分钟) | 前端内存/LocalStorage | 中等(需防泄露) |

| 长 Token (Refresh Token) | 刷新短 Token | 长(如7天) | HttpOnly Cookie 或数据库 | 高(需严格保护) |


2. 核心流程

2.1 用户登录认证

http POST /login HTTP/1.1 Content-Type: application/json { "username": "user", "password": "pass" }

http HTTP/1.1 200 OK Set-Cookie: refresh_token=abc123xyz; HttpOnly; Secure; SameSite=Strict Content-Type: application/json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx", "expires_in": 900 }

2.2 短 Token 刷新流程

http POST /refresh-token HTTP/1.1 Cookie: refresh_token=abc123xyz // 浏览器自动携带 HttpOnly Cookie

http HTTP/1.1 200 OK Set-Cookie: refresh_token=new_abc123xyz; HttpOnly; Secure; SameSite=Strict Content-Type: application/json { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.new_token", "expires_in": 900 }


3. 安全措施

3.1 长 Token 存储

  • 数据库存储:

  • 存储长 Token 的哈希值(如 bcrypt 或 sha256),避免明文存储。

  • 绑定用户 ID、设备指纹(IP + User-Agent 哈希)、过期时间。

  • 示例 SQL:

sql CREATE TABLE refresh_tokens ( id SERIAL PRIMARY KEY, user_id INT NOT NULL, token_hash TEXT NOT NULL, -- 哈希后的长 Token fingerprint TEXT, -- 设备指纹 expires_at TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

3.2 长 Token 传输

  • HttpOnly Cookie:

  • 通过 Set-Cookie 头部传输,防止 XSS 攻击。

  • 设置 Secure(仅 HTTPS)、SameSite=Strict(防止 CSRF)。

3.3 Token 旋转(Rotation)

  • 每次刷新生成新长 Token:

  • 旧长 Token 立即失效,防止长期泄露。

  • 示例逻辑:

javascript // 服务端生成新长 Token 并更新数据库 const newRefreshToken = crypto.randomBytes(64).toString('hex'); const hashedToken = hash(newRefreshToken); db.query( 'UPDATE refresh_tokens SET token_hash = $1, updated_at = NOW() WHERE user_id = $2', [hashedToken, userId] );

3.4 设备指纹绑定

  • 验证设备信息:

  • 检查长 Token 是否与当前设备指纹(IP + User-Agent)匹配。

  • 示例代码:

javascript function getFingerprint(req) { return crypto.createHash('sha256') .update(req.ip + req.headers['user-agent']) .digest('hex'); } const storedFingerprint = db.getFingerprint(refreshToken); if (storedFingerprint !== getFingerprint(req)) { throw new Error('Invalid device fingerprint'); }

3.5 短 Token 黑名单(可选)

  • 短期吊销:

  • 短 Token 过期后加入 Redis 黑名单,防止重复使用。

  • 示例:

javascript // Redis 缓存短 Token 黑名单(TTL = 短 Token 剩余时间) redis.setex(oldAccessToken, remainingTTL, 'revoked');


4. 代码示例(Node.js + JWT)

4.1 生成 Token

javascript const jwt = require('jsonwebtoken'); const crypto = require('crypto'); // 生成短 Token function generateAccessToken(userId, permissions) { return jwt.sign( { user_id: userId, permissions }, process.env.JWT_SECRET, { expiresIn: '15m' } ); } // 生成长 Token function generateRefreshToken() { return crypto.randomBytes(64).toString('hex'); }

4.2 刷新 Token 接口

javascript app.post('/refresh-token', (req, res) => { const refreshToken = req.cookies.refresh_token; if (!refreshToken) return res.status(403).send('Missing refresh token'); // 1. 验证长 Token 是否有效 const hashedToken = hash(refreshToken); const tokenRecord = db.query( 'SELECT * FROM refresh_tokens WHERE token_hash = $1', [hashedToken] ); if (!tokenRecord || tokenRecord.expires_at < new Date()) { return res.status(403).send('Invalid refresh token'); } // 2. 生成新短 Token const newAccessToken = generateAccessToken(tokenRecord.user_id, ['read']); // 3. 可选:生成新长 Token(旋转机制) const newRefreshToken = generateRefreshToken(); db.query( 'UPDATE refresh_tokens SET token_hash = $1 WHERE user_id = $2', [hash(newRefreshToken), tokenRecord.user_id] ); // 4. 返回新短 Token res.cookie('refresh_token', newRefreshToken, { httpOnly: true, secure: true }); res.json({ access_token: newAccessToken }); });


5. 常见问题

5.1 为什么不能一起返回长短 Token?

  • 风险:长 Token 泄露可能导致长期账户控制。

  • 正确做法:长 Token 通过 HttpOnly Cookie 传输,短 Token 通过 JSON 响应返回。

5.2 长 Token 被盗用怎么办?

  • 检测异常:绑定设备指纹,发现异常 IP/User-Agent 时强制登出。

  • 立即吊销:删除数据库中的长 Token,并将短 Token 加入黑名单。

5.3 用户主动登出如何处理?

  • 服务端:删除数据库中的长 Token。

  • 客户端:清除本地存储的短 Token 和 Cookie。


6. 总结

  • 短 Token:无状态 JWT,存储在前端,用于接口鉴权。

  • 长 Token:存储在数据库,通过 HttpOnly Cookie 传输,用于刷新短 Token。

  • 核心安全原则:

  • 长 Token 必须严格保护(哈希存储 + HttpOnly Cookie)。

  • 绑定设备指纹 + Token 旋转机制。

  • 短 Token 黑名单(可选)。

通过分层保护,确保即使短 Token 泄露,攻击者也无法长期控制用户账户。


本文由萧兮的博客原创发布,欢迎转载,转载务必保留原文链接。

萧兮的博客https://www.20010515.xyz · 原文:https://www.20010515.xyz/posts/b8a88f23-ab4a-4d44-973b-85fe46fea9b3