不同环境JWT参数配置
- 密钥管理:
- 开发环境:
- 可以使用一个相对简单且固定的密钥,例如在
.env.development
文件中定义JWT_SECRET='dev_secret'
,方便开发过程中进行调试,同时在开发环境代码仓库中忽略.env.development
文件,避免密钥泄露。
- 在Node.js项目中,可以使用
dotenv
库来加载环境变量,代码示例:
const dotenv = require('dotenv');
dotenv.config({ path: '.env.development' });
const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET;
// 使用JWT相关操作,如验证token
function verifyToken(token) {
return jwt.verify(token, secret);
}
- 测试环境:
- 同样在
.env.test
文件中定义JWT_SECRET
,密钥应该与开发环境不同,且具有一定复杂度,例如JWT_SECRET='test_secure_secret123!@#'
。同样忽略.env.test
文件,防止测试密钥泄露。
- 加载环境变量方式与开发环境类似,
dotenv.config({ path: '.env.test' });
- 生产环境:
- 使用强密钥,最好从安全的环境变量管理系统(如AWS Secrets Manager、Google Cloud Secret Manager等)获取。例如在AWS环境中,通过AWS SDK获取密钥:
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
async function getJwtSecret() {
const params = {
SecretId: 'production - jwt - secret'
};
try {
const data = await secretsManager.getSecretValue(params).promise();
return data.SecretString;
} catch (error) {
throw new Error('Failed to get JWT secret from Secrets Manager');
}
}
- 其他参数配置:
- 过期时间:
- 开发环境:可以设置较短的过期时间,如5分钟(
expiresIn: '5m'
),方便快速发现身份验证相关问题。
- 测试环境:设置适中的过期时间,如15分钟(
expiresIn: '15m'
),以平衡测试效率和模拟实际场景。
- 生产环境:根据业务需求设置合理的过期时间,对于一些长期有效的token(如用户登录token)可以设置为1小时到1天不等(
expiresIn: '1h'
或expiresIn: '1d'
),对于短期的操作(如密码重置链接)设置几分钟的过期时间。
安全优化措施防止JWT被破解或滥用
- 密钥安全:
- 始终保持密钥的保密性,如上述在不同环境对密钥的妥善管理,绝不将密钥硬编码在代码中。
- 定期更换生产环境的密钥,例如每月或每季度更换一次,降低密钥泄露带来的风险。
- token存储安全:
- 在客户端,将JWT存储在HTTP - only的Cookie中,防止通过JavaScript访问Cookie,从而避免XSS攻击窃取JWT。例如在Node.js的Express应用中设置Cookie:
const express = require('express');
const app = express();
app.use((req, res, next) => {
const token = generateJwtToken();
res.cookie('jwt', token, { httpOnly: true });
next();
});
- 或者在LocalStorage或SessionStorage存储时,对JWT进行加密处理。
- 验证与签名:
- 始终对收到的JWT进行严格验证,不仅验证签名,还要验证过期时间、受众(
aud
)、签发者(iss
)等声明。例如:
const jwt = require('jsonwebtoken');
function verifyToken(token) {
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
issuer: 'your - issuer - name',
audience: 'your - audience - name'
});
return decoded;
} catch (error) {
return null;
}
}
- 使用合适的签名算法,推荐使用RS256(基于RSA的签名算法)或ES256(基于椭圆曲线的签名算法),避免使用容易被破解的HS256(对称密钥签名算法),特别是在密钥较长且难以管理的情况下。
- 防止重放攻击:
- 在JWT中添加唯一标识符(如
jti
声明),并在服务器端维护一个已使用的JWT列表,每次验证JWT时检查jti
是否已被使用过。例如:
const usedJwtList = [];
function verifyToken(token) {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
if (usedJwtList.includes(decoded.jti)) {
throw new Error('Replay attack detected');
}
usedJwtList.push(decoded.jti);
return decoded;
}
- 限制token使用范围:
- 在JWT中添加权限相关声明(如
scope
),服务器端根据scope
验证用户是否有权限执行相关操作。例如,一个用户JWT可能有scope: 'read:user'
权限,只能进行读取用户信息操作,而不能进行修改操作。在API路由处理中进行权限验证:
function requireScope(requiredScope) {
return (req, res, next) => {
const token = req.cookies.jwt;
const decoded = jwt.verify(token, process.env.JWT_SECRET);
if (!decoded.scope.includes(requiredScope)) {
return res.status(403).send('Forbidden');
}
next();
};
}
app.get('/user', requireScope('read:user'), (req, res) => {
// 处理获取用户信息逻辑
});