安全增强: - 新增 SSRF、XXE、模板注入、敏感路径探测检测规则 - security/constants.py: 添加新的威胁类型和检测模式 - security/threat_detector.py: 实现新检测逻辑 删除密码重置申请功能: - 移除 /api/password_resets 相关API - 删除 password_reset_requests 数据库表 - 前端移除密码重置申请页面和菜单 - 用户只能通过邮��找回密码,未绑定邮箱需联系管理员 登录提醒全局开关: - email_service.py: 添加 login_alert_enabled 字段 - routes/api_auth.py: 检查开关状态再发送登录提醒 - EmailPage.vue: 添加新设备登录提醒开关 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
147 lines
5.0 KiB
Python
147 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
# ==================== Threat Types ====================
|
|
|
|
THREAT_TYPE_JNDI_INJECTION = "jndi_injection"
|
|
THREAT_TYPE_NESTED_EXPRESSION = "nested_expression"
|
|
THREAT_TYPE_SQL_INJECTION = "sql_injection"
|
|
THREAT_TYPE_XSS = "xss"
|
|
THREAT_TYPE_PATH_TRAVERSAL = "path_traversal"
|
|
THREAT_TYPE_COMMAND_INJECTION = "command_injection"
|
|
THREAT_TYPE_SSRF = "ssrf"
|
|
THREAT_TYPE_XXE = "xxe"
|
|
THREAT_TYPE_TEMPLATE_INJECTION = "template_injection"
|
|
THREAT_TYPE_SENSITIVE_PATH_PROBE = "sensitive_path_probe"
|
|
|
|
|
|
# ==================== Scores ====================
|
|
|
|
SCORE_JNDI_DIRECT = 100
|
|
SCORE_JNDI_OBFUSCATED = 100
|
|
SCORE_NESTED_EXPRESSION = 80
|
|
SCORE_SQL_INJECTION = 90
|
|
SCORE_XSS = 70
|
|
SCORE_PATH_TRAVERSAL = 60
|
|
SCORE_COMMAND_INJECTION = 85
|
|
SCORE_SSRF = 75
|
|
SCORE_XXE = 85
|
|
SCORE_TEMPLATE_INJECTION = 70
|
|
SCORE_SENSITIVE_PATH_PROBE = 40
|
|
|
|
|
|
# ==================== JNDI (Log4j) ====================
|
|
#
|
|
# - Direct: ${jndi:ldap://...} / ${jndi:rmi://...} => 100
|
|
# - Obfuscated: ${${xxx:-j}${xxx:-n}...:ldap://...} => detect
|
|
# - Nested expression: ${${...}} => 80
|
|
|
|
JNDI_DIRECT_PATTERN = r"\$\{\s*jndi\s*:\s*(?:ldap|rmi)\s*://"
|
|
|
|
# Common Log4j "default value" obfuscation variants:
|
|
# ${${::-j}${::-n}${::-d}${::-i}:ldap://...}
|
|
# ${${foo:-j}${bar:-n}${baz:-d}${qux:-i}:rmi://...}
|
|
JNDI_OBFUSCATED_PATTERN = (
|
|
r"\$\{\s*"
|
|
r"(?:\$\{[^{}]{0,50}:-j\}|\$\{::-[jJ]\})\s*"
|
|
r"(?:\$\{[^{}]{0,50}:-n\}|\$\{::-[nN]\})\s*"
|
|
r"(?:\$\{[^{}]{0,50}:-d\}|\$\{::-[dD]\})\s*"
|
|
r"(?:\$\{[^{}]{0,50}:-i\}|\$\{::-[iI]\})\s*"
|
|
r":\s*(?:ldap|rmi)\s*://"
|
|
)
|
|
|
|
NESTED_EXPRESSION_PATTERN = r"\$\{\s*\$\{"
|
|
|
|
|
|
# ==================== SQL Injection ====================
|
|
|
|
SQLI_UNION_SELECT_PATTERN = r"\bunion\b\s+(?:all\s+)?\bselect\b"
|
|
SQLI_OR_1_EQ_1_PATTERN = r"\bor\b\s+1\s*=\s*1\b"
|
|
|
|
|
|
# ==================== XSS ====================
|
|
|
|
XSS_SCRIPT_TAG_PATTERN = r"<\s*script\b"
|
|
XSS_JS_PROTOCOL_PATTERN = r"javascript\s*:"
|
|
XSS_INLINE_EVENT_HANDLER_PATTERN = r"\bon\w+\s*="
|
|
|
|
|
|
# ==================== Path Traversal ====================
|
|
|
|
PATH_TRAVERSAL_PATTERN = r"(?:\.\./|\.\.\\)+"
|
|
|
|
|
|
# ==================== Command Injection ====================
|
|
|
|
CMD_INJECTION_OPERATOR_WITH_CMD_PATTERN = (
|
|
r"(?:;|&&|\|\||\|)\s*"
|
|
r"(?:bash|sh|zsh|cmd|powershell|pwsh|curl|wget|nc|netcat|python|perl|ruby|php|node|cat|ls|id|whoami|uname|rm)\b"
|
|
)
|
|
CMD_INJECTION_SUBSHELL_PATTERN = r"(?:`[^`]{1,200}`|\$\([^)]{1,200}\))"
|
|
|
|
|
|
# ==================== SSRF ====================
|
|
|
|
SSRF_LOCALHOST_URL_PATTERN = r"\bhttps?\s*:\s*//\s*(?:127\.0\.0\.1\b|localhost\b|0\.0\.0\.0\b)"
|
|
SSRF_INTERNAL_IP_URL_PATTERN = r"\bhttps?\s*:\s*//\s*(?:10\.|192\.168\.|172\.(?:1[6-9]|2[0-9]|3[0-1])\.)"
|
|
SSRF_DANGEROUS_PROTOCOL_PATTERN = r"\b(?:file|gopher|dict)\s*:\s*//"
|
|
|
|
|
|
# ==================== XXE ====================
|
|
|
|
XXE_DOCTYPE_PATTERN = r"<!\s*doctype\b|\bdoctype\b"
|
|
XXE_ENTITY_PATTERN = r"<!\s*entity\b|\bentity\b"
|
|
XXE_SYSTEM_PUBLIC_PATTERN = r"\b(?:system|public)\b"
|
|
|
|
|
|
# ==================== Template Injection ====================
|
|
|
|
TEMPLATE_JINJA_EXPR_PATTERN = r"\{\{\s*[^}]{0,200}\s*\}\}"
|
|
TEMPLATE_JINJA_STMT_PATTERN = r"\{%\s*[^%]{0,200}\s*%\}"
|
|
TEMPLATE_VELOCITY_DIRECTIVE_PATTERN = r"#\s*(?:set|if)\b"
|
|
|
|
|
|
# ==================== Sensitive Path Probing ====================
|
|
|
|
SENSITIVE_PATH_DOTFILES_PATTERN = r"/\.(?:git|svn|env)(?:/|\b|$)"
|
|
SENSITIVE_PATH_PROBE_PATTERN = r"/(?:actuator|phpinfo|wp-admin)(?:/|\b|$)"
|
|
|
|
|
|
# ==================== Compiled Regex ====================
|
|
|
|
_FLAGS = re.IGNORECASE | re.MULTILINE
|
|
|
|
JNDI_DIRECT_RE = re.compile(JNDI_DIRECT_PATTERN, _FLAGS)
|
|
JNDI_OBFUSCATED_RE = re.compile(JNDI_OBFUSCATED_PATTERN, _FLAGS)
|
|
NESTED_EXPRESSION_RE = re.compile(NESTED_EXPRESSION_PATTERN, _FLAGS)
|
|
|
|
SQLI_UNION_SELECT_RE = re.compile(SQLI_UNION_SELECT_PATTERN, _FLAGS)
|
|
SQLI_OR_1_EQ_1_RE = re.compile(SQLI_OR_1_EQ_1_PATTERN, _FLAGS)
|
|
|
|
XSS_SCRIPT_TAG_RE = re.compile(XSS_SCRIPT_TAG_PATTERN, _FLAGS)
|
|
XSS_JS_PROTOCOL_RE = re.compile(XSS_JS_PROTOCOL_PATTERN, _FLAGS)
|
|
XSS_INLINE_EVENT_HANDLER_RE = re.compile(XSS_INLINE_EVENT_HANDLER_PATTERN, _FLAGS)
|
|
|
|
PATH_TRAVERSAL_RE = re.compile(PATH_TRAVERSAL_PATTERN, _FLAGS)
|
|
|
|
CMD_INJECTION_OPERATOR_WITH_CMD_RE = re.compile(CMD_INJECTION_OPERATOR_WITH_CMD_PATTERN, _FLAGS)
|
|
CMD_INJECTION_SUBSHELL_RE = re.compile(CMD_INJECTION_SUBSHELL_PATTERN, _FLAGS)
|
|
|
|
SSRF_LOCALHOST_URL_RE = re.compile(SSRF_LOCALHOST_URL_PATTERN, _FLAGS)
|
|
SSRF_INTERNAL_IP_URL_RE = re.compile(SSRF_INTERNAL_IP_URL_PATTERN, _FLAGS)
|
|
SSRF_DANGEROUS_PROTOCOL_RE = re.compile(SSRF_DANGEROUS_PROTOCOL_PATTERN, _FLAGS)
|
|
|
|
XXE_DOCTYPE_RE = re.compile(XXE_DOCTYPE_PATTERN, _FLAGS)
|
|
XXE_ENTITY_RE = re.compile(XXE_ENTITY_PATTERN, _FLAGS)
|
|
XXE_SYSTEM_PUBLIC_RE = re.compile(XXE_SYSTEM_PUBLIC_PATTERN, _FLAGS)
|
|
|
|
TEMPLATE_JINJA_EXPR_RE = re.compile(TEMPLATE_JINJA_EXPR_PATTERN, _FLAGS)
|
|
TEMPLATE_JINJA_STMT_RE = re.compile(TEMPLATE_JINJA_STMT_PATTERN, _FLAGS)
|
|
TEMPLATE_VELOCITY_DIRECTIVE_RE = re.compile(TEMPLATE_VELOCITY_DIRECTIVE_PATTERN, _FLAGS)
|
|
|
|
SENSITIVE_PATH_DOTFILES_RE = re.compile(SENSITIVE_PATH_DOTFILES_PATTERN, _FLAGS)
|
|
SENSITIVE_PATH_PROBE_RE = re.compile(SENSITIVE_PATH_PROBE_PATTERN, _FLAGS)
|