面试题答案
一键面试1. JWT可能面临的安全风险
- 信息泄露风险:
- 风险描述:如果JWT在传输过程中未加密,其包含的敏感信息(如用户ID、角色等)可能被截获并获取。因为JWT通常是Base64编码,很容易解码查看其中内容。
- 防范措施:在传输过程中使用HTTPS协议,对整个通信链路进行加密,防止中间人窃听获取JWT内容。
- 密钥泄露风险:
- 风险描述:JWT的签名验证依赖于密钥,如果密钥泄露,攻击者可以伪造合法的JWT,从而绕过认证机制,访问受保护资源。
- 防范措施:妥善保管密钥,密钥应足够复杂且保密。避免在代码中硬编码密钥,可将密钥存储在安全的配置文件或密钥管理服务(如HashiCorp Vault)中,并严格控制对密钥的访问权限。
- 重放攻击风险:
- 风险描述:攻击者截获合法的JWT后,可以多次使用该JWT访问受保护资源,而服务器无法识别这是重复使用的令牌。
- 防范措施:在服务端维护一个已使用JWT的黑名单或采用带有过期时间(exp)声明的JWT,并在每次验证时检查令牌是否过期或已在黑名单中。
2. 后端开发确保JWT安全性的实际代码示例(以Python Flask和PyJWT库为例)
from flask import Flask, request, jsonify
import jwt
import datetime
from functools import wraps
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key' # 实际应用中应从安全配置获取
# 模拟用户数据
users = {
'user1': 'password1'
}
def token_required(f):
@wraps(f)
def decorated(*args, **kwargs):
token = None
if 'x-access-token' in request.headers:
token = request.headers['x-access-token']
if not token:
return jsonify({'message': 'Token is missing!'}), 401
try:
data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
except jwt.ExpiredSignatureError:
return jsonify({'message': 'Token has expired!'}), 401
except jwt.InvalidTokenError:
return jsonify({'message': 'Token is invalid!'}), 401
return f(*args, **kwargs)
return decorated
@app.route('/login')
def login():
auth = request.authorization
if not auth or not auth.username or not auth.password:
return jsonify({'message': 'Could not verify'}), 401
if auth.username in users and users[auth.username] == auth.password:
token = jwt.encode({'user': auth.username, 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)},
app.config['SECRET_KEY'], algorithm='HS256')
return jsonify({'token': token})
return jsonify({'message': 'Could not verify'}), 401
@app.route('/protected')
@token_required
def protected():
return jsonify({'message': 'This is a protected route'})
if __name__ == '__main__':
app.run(debug=True)
在上述代码中:
- 密钥管理:
app.config['SECRET_KEY']
用于设置JWT签名密钥,实际应用中应从安全配置中获取,而不是直接写在代码中。 - 过期时间设置:在生成JWT时,通过
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
设置了令牌的过期时间为30分钟,有效防止重放攻击。 - 令牌验证:
token_required
装饰器用于验证请求中的JWT,捕获ExpiredSignatureError
和InvalidTokenError
异常,分别处理过期和无效的令牌,确保只有合法且未过期的令牌才能访问受保护路由。