修复多项安全漏洞
安全修复清单: 1. 验证码改为图片方式返回,防止明文泄露 2. CORS配置从环境变量读取,不再使用通配符"*" 3. VIP API添加@admin_required装饰器,统一认证 4. 用户登录统一错误消息,防止用户枚举 5. IP限流不再信任X-Forwarded-For头,防止伪造绕过 6. 密码强度要求提升(8位+字母+数字) 7. 日志不���记录完整session/cookie内容,防止敏感信息泄露 8. XSS防护:日志输出和Bug反馈内容转义HTML 9. SQL注入防护:LIKE查询参数转义 10. 路径遍历防护:截图目录白名单验证 11. 验证码重放防护:验证前删除验证码 12. 数据库连接池健康检查 13. 正则DoS防护:限制数字匹配长度 14. Account类密码私有化,__repr__不暴露密码 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -240,12 +240,15 @@ def validate_username(username):
|
||||
return True, None
|
||||
|
||||
|
||||
def validate_password(password):
|
||||
def validate_password(password, require_complexity=True):
|
||||
"""
|
||||
验证密码强度
|
||||
|
||||
安全修复:增强密码强度要求
|
||||
|
||||
Args:
|
||||
password: 密码
|
||||
require_complexity: 是否要求复杂度(默认True)
|
||||
|
||||
Returns:
|
||||
tuple: (is_valid, error_message)
|
||||
@@ -253,19 +256,19 @@ def validate_password(password):
|
||||
if not password:
|
||||
return False, "密码不能为空"
|
||||
|
||||
if len(password) < 6:
|
||||
return False, "密码长度不能少于6个字符"
|
||||
if len(password) < 8: # 安全修复:最少8位
|
||||
return False, "密码长度不能少于8个字符"
|
||||
|
||||
if len(password) > 128:
|
||||
return False, "密码长度不能超过128个字符"
|
||||
|
||||
# 可选:强制密码复杂度
|
||||
# has_upper = bool(re.search(r'[A-Z]', password))
|
||||
# has_lower = bool(re.search(r'[a-z]', password))
|
||||
# has_digit = bool(re.search(r'\d', password))
|
||||
#
|
||||
# if not (has_upper and has_lower and has_digit):
|
||||
# return False, "密码必须包含大写字母、小写字母和数字"
|
||||
# 安全修复:启用密码复杂度要求
|
||||
if require_complexity:
|
||||
has_letter = bool(re.search(r'[a-zA-Z]', password))
|
||||
has_digit = bool(re.search(r'\d', password))
|
||||
|
||||
if not (has_letter and has_digit):
|
||||
return False, "密码必须包含字母和数字"
|
||||
|
||||
return True, None
|
||||
|
||||
@@ -392,20 +395,28 @@ def check_security_config():
|
||||
|
||||
# ==================== 辅助函数 ====================
|
||||
|
||||
def get_client_ip():
|
||||
def get_client_ip(trust_proxy=False):
|
||||
"""
|
||||
获取客户端真实IP地址
|
||||
|
||||
安全修复:默认不信任代理头,防止IP伪造绕过限流
|
||||
|
||||
Args:
|
||||
trust_proxy: 是否信任代理头(仅在已知可信代理后设置为True)
|
||||
|
||||
Returns:
|
||||
str: IP地址
|
||||
"""
|
||||
# 检查代理头
|
||||
if request.headers.get('X-Forwarded-For'):
|
||||
return request.headers.get('X-Forwarded-For').split(',')[0].strip()
|
||||
elif request.headers.get('X-Real-IP'):
|
||||
return request.headers.get('X-Real-IP')
|
||||
else:
|
||||
return request.remote_addr
|
||||
# 安全说明:X-Forwarded-For 可被伪造
|
||||
# 仅在确认请求来自可信代理时才使用代理头
|
||||
if trust_proxy:
|
||||
if request.headers.get('X-Forwarded-For'):
|
||||
return request.headers.get('X-Forwarded-For').split(',')[0].strip()
|
||||
elif request.headers.get('X-Real-IP'):
|
||||
return request.headers.get('X-Real-IP')
|
||||
|
||||
# 默认使用remote_addr(更安全但可能是代理IP)
|
||||
return request.remote_addr
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user