fix: 修复 JWT 幽灵令牌漏洞,新增 Dify 权限过滤服务
This commit is contained in:
@ -5,6 +5,43 @@ from flask import jsonify, g, request, current_app, has_request_context
|
||||
import logging
|
||||
import json
|
||||
|
||||
def _verify_user_active():
|
||||
"""
|
||||
JWT「幽灵令牌」安全漏洞修复:
|
||||
在 Token 签名验证通过之后,进一步检查用户在数据库中是否仍然存在且未被禁用。
|
||||
|
||||
调用时机:login_required / permission_required 装饰器中,
|
||||
在 verify_jwt_in_request() 成功之后立即调用。
|
||||
|
||||
返回 True → 用户正常,放行
|
||||
返回 False → 用户已从数据库删除或被禁用,阻断请求
|
||||
"""
|
||||
try:
|
||||
claims = get_jwt()
|
||||
user_id = claims.get('sub')
|
||||
if user_id is None:
|
||||
return True
|
||||
|
||||
from app.models.system import SysUser
|
||||
user = SysUser.query.get(user_id)
|
||||
if user is None:
|
||||
current_app.logger.warning(
|
||||
f"🚫 [Ghost Token Blocked] user_id={user_id} not found in database (deleted account)"
|
||||
)
|
||||
return False
|
||||
|
||||
if user.status != 'active':
|
||||
current_app.logger.warning(
|
||||
f"🚫 [Token Blocked] user_id={user_id} status={user.status} (disabled account)"
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"User active check error: {e}")
|
||||
return True # 出错时 fail-open,避免数据库故障导致全站不可用
|
||||
|
||||
|
||||
def _verify_token_in_redis():
|
||||
"""
|
||||
验证当前 Token 是否与 Redis 中存储的 Token 一致(单设备登录互踢)
|
||||
@ -67,7 +104,10 @@ def role_required(*roles):
|
||||
return wrapper
|
||||
|
||||
def login_required(fn):
|
||||
"""验证 JWT 令牌是否存在且有效"""
|
||||
"""
|
||||
验证 JWT 令牌是否存在且有效,并检查用户是否仍在数据库中且未被禁用。
|
||||
双重防护:1) Token 签名验证 2) 数据库用户存在性 3) Redis 单设备互踢
|
||||
"""
|
||||
@wraps(fn)
|
||||
def decorator(*args, **kwargs):
|
||||
try:
|
||||
@ -76,6 +116,10 @@ def login_required(fn):
|
||||
logging.warning(f"JWT verification failed: {e}")
|
||||
return jsonify(msg='登录已过期,请重新登录'), 401
|
||||
|
||||
# ★ 幽灵令牌漏洞修复:检查用户是否已从数据库删除或被禁用
|
||||
if not _verify_user_active():
|
||||
return jsonify(msg='账号已失效(已删除或已禁用),请重新登录'), 401
|
||||
|
||||
if not _verify_token_in_redis():
|
||||
return _raise_token_mismatch_error()
|
||||
|
||||
@ -83,7 +127,7 @@ def login_required(fn):
|
||||
return decorator
|
||||
|
||||
def permission_required(permission_code):
|
||||
"""检查当前用户是否拥有指定权限码"""
|
||||
"""检查当前用户是否拥有指定权限码,同时检查用户是否仍然有效"""
|
||||
def wrapper(fn):
|
||||
@wraps(fn)
|
||||
def decorator(*args, **kwargs):
|
||||
@ -93,6 +137,10 @@ def permission_required(permission_code):
|
||||
logging.warning(f"JWT verification failed: {e}")
|
||||
return jsonify(msg='登录已过期,请重新登录'), 401
|
||||
|
||||
# ★ 幽灵令牌漏洞修复:检查用户是否已从数据库删除或被禁用
|
||||
if not _verify_user_active():
|
||||
return jsonify(msg='账号已失效(已删除或已禁用),请重新登录'), 401
|
||||
|
||||
if not _verify_token_in_redis():
|
||||
return _raise_token_mismatch_error()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user