修复多项安全漏洞

安全修复清单:
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:
2025-12-11 17:53:48 +08:00
parent a4b7074634
commit 70cd95c366
10 changed files with 256 additions and 101 deletions

View File

@@ -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__':