fix: 审核引擎优化 + 执行结果结构化展示

后端审核规则修复:
- Redis SEC-001: SET/DEL等常规命令不再误报AUTH要求,改为仅对管理级命令WARNING
- Redis SEC-003: 降级为INFO,排除已由CMD-001拦截的FLUSHDB/FLUSHALL
- Redis key提取: 排除CONFIG/ACL等管理命令,不再把子命令参数误认为key名
- MySQL SEC-006: 新增GRANT ALL/REVOKE ALL全局权限拦截
- MySQL SEC-007: 新增LOAD DATA/LOAD XML拦截
- MySQL SEC-008: 新增SLEEP()/BENCHMARK()时间盲注拦截
- MySQL SEC-009: 新增INTO OUTFILE/DUMPFILE文件写入拦截

前端执行结果结构化:
- TicketDetailPage执行结果从原始JSON改为结构化展示
- 解析JSON展示: 状态徽章+影响行数+耗时+验证状态
- Errors/Warnings逐条渲染: 红色错误框+黄色警告框+具体消息
- 删除废弃的executeStats/renderExecuteStats

其他: 审核规则6分组/慢查询移除/查询数据重命名/AuditLogs修复
测试: 1040 passed, TSC零错误
This commit is contained in:
logan committed 2026-05-24 01:31:33 +08:00
1 parent 9f56e866f2
commit 4ac2528f8e
19 files changed
+1202 -325

No files matched your search

+100 -2
View File
@@ -2090,12 +2090,110 @@ def check_mysql_sec_005(sql_clean: str, sql_upper: str, report: AuditReportV2, r
# ═══════════════════════════════════════════════════
# 模块总结
# ── SEC-006: 权限相关高危语句拦截 ──
@register_rule(AuditRuleV2(
code="MYSQL-SEC-006",
name="DangerousPrivilegeStatement",
category=RuleCategory.SECURITY,
severity=Severity.ERROR,
db_type="mysql",
description="拦截 GRANT ALL / REVOKE ALL 等全局权限变更操作",
config={"enabled": True},
message_template="禁止执行 '{keyword}' 全局权限操作,请联系 DBA 通过权限管理流程申请",
))
def check_mysql_sec_006(sql_clean: str, sql_upper: str, report: AuditReportV2, rule: AuditRuleV2) -> None:
"""全局权限语句拦截。"""
# GRANT ALL / GRANT ALL PRIVILEGES
if re.search(r'\bGRANT\s+ALL\b', sql_upper):
report.findings.append(AuditFindingV2(
rule_code=rule.code, rule_name=rule.name, level=rule.severity,
message=rule.message_template.format(keyword="GRANT ALL"),
))
# REVOKE ALL
elif re.search(r'\bREVOKE\s+ALL\b', sql_upper):
report.findings.append(AuditFindingV2(
rule_code=rule.code, rule_name=rule.name, level=rule.severity,
message=rule.message_template.format(keyword="REVOKE ALL"),
))
# ── SEC-007: LOAD DATA / LOAD XML 拦截 ──
@register_rule(AuditRuleV2(
code="MYSQL-SEC-007",
name="BlockLoadData",
category=RuleCategory.SECURITY,
severity=Severity.ERROR,
db_type="mysql",
description="禁止 LOAD DATA / LOAD XML 操作,存在安全风险且可能导入大量数据",
config={"enabled": True},
message_template="禁止使用 '{keyword}',该操作存在安全风险,请使用 INSERT 批量导入",
))
def check_mysql_sec_007(sql_clean: str, sql_upper: str, report: AuditReportV2, rule: AuditRuleV2) -> None:
"""LOAD DATA/LOAD XML 拦截。"""
if re.search(r'\bLOAD\s+DATA\b', sql_upper):
report.findings.append(AuditFindingV2(
rule_code=rule.code, rule_name=rule.name, level=rule.severity,
message=rule.message_template.format(keyword="LOAD DATA"),
))
elif re.search(r'\bLOAD\s+XML\b', sql_upper):
report.findings.append(AuditFindingV2(
rule_code=rule.code, rule_name=rule.name, level=rule.severity,
message=rule.message_template.format(keyword="LOAD XML"),
))
# ── SEC-008: SLEEP / BENCHMARK 注入拦截 ──
@register_rule(AuditRuleV2(
code="MYSQL-SEC-008",
name="BlockTimeBasedInjection",
category=RuleCategory.SECURITY,
severity=Severity.ERROR,
db_type="mysql",
description="拦截 SLEEP() / BENCHMARK() 等时间盲注函数",
config={"enabled": True},
message_template="禁止使用 '{func}()' 函数,疑似时间盲注攻击",
))
def check_mysql_sec_008(sql_clean: str, sql_upper: str, report: AuditReportV2, rule: AuditRuleV2) -> None:
"""时间盲注函数拦截。"""
if re.search(r'\bSLEEP\s*\(', sql_upper):
report.findings.append(AuditFindingV2(
rule_code=rule.code, rule_name=rule.name, level=rule.severity,
message=rule.message_template.format(func="SLEEP"),
))
if re.search(r'\bBENCHMARK\s*\(', sql_upper):
report.findings.append(AuditFindingV2(
rule_code=rule.code, rule_name=rule.name, level=rule.severity,
message=rule.message_template.format(func="BENCHMARK"),
))
# ── SEC-009: INTO OUTFILE / INTO DUMPFILE 拦截 ──
@register_rule(AuditRuleV2(
code="MYSQL-SEC-009",
name="BlockIntoOutfile",
category=RuleCategory.SECURITY,
severity=Severity.ERROR,
db_type="mysql",
description="禁止 INTO OUTFILE / INTO DUMPFILE,防止写入 WebShell 或导出敏感数据",
config={"enabled": True},
message_template="禁止使用 '{keyword}',该操作可写入文件系统,存在严重安全风险",
))
def check_mysql_sec_009(sql_clean: str, sql_upper: str, report: AuditReportV2, rule: AuditRuleV2) -> None:
"""INTO OUTFILE/DUMPFILE 拦截。"""
if re.search(r'\bINTO\s+(OUT|DUMP)FILE\b', sql_upper):
keyword = "INTO OUTFILE" if "OUTFILE" in sql_upper else "INTO DUMPFILE"
report.findings.append(AuditFindingV2(
rule_code=rule.code, rule_name=rule.name, level=rule.severity,
message=rule.message_template.format(keyword=keyword),
))
# ═══════════════════════════════════════════════════
# 总计 63 条规则:
# 总计 67 条规则:
# - DDL 规则: 36 条 (MYSQL-DDL-001 ~ MYSQL-DDL-036)
# - DML 规则: 9 条 (MYSQL-DML-001 ~ MYSQL-DML-009)
# - Online-DDL 规则: 3 条 (MYSQL-OSC-001 ~ MYSQL-OSC-003)
# - 命名规则: 5 条 (MYSQL-NAM-001 ~ MYSQL-NAM-005)
# - 性能规则: 5 条 (MYSQL-PERF-001 ~ MYSQL-PERF-005)
# - 安全规则: 5 条 (MYSQL-SEC-001 ~ MYSQL-SEC-005)
# - 安全规则: 9 条 (MYSQL-SEC-001 ~ MYSQL-SEC-009)
# ═══════════════════════════════════════════════════