fix(report_generator): 转义HTML特殊字符以防止XSS攻击
添加_html_escape方法并对报告中的用户输入数据进行转义处理,包括代码片段、描述、建议、标题和文件路径,以提高安全性
This commit is contained in:
parent
220b5f793a
commit
89ebd4d797
|
|
@ -3,6 +3,7 @@ PDF 报告生成服务 - 专业审计版 (WeasyPrint)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
import html
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List, Dict, Any
|
from typing import List, Dict, Any
|
||||||
import math
|
import math
|
||||||
|
|
@ -397,19 +398,26 @@ class ReportGenerator:
|
||||||
return ""
|
return ""
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _escape_html(cls, text: str) -> str:
|
||||||
|
"""安全转义 HTML 特殊字符"""
|
||||||
|
if text is None:
|
||||||
|
return None
|
||||||
|
return html.escape(str(text))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _process_issues(cls, issues: List[Dict]) -> List[Dict]:
|
def _process_issues(cls, issues: List[Dict]) -> List[Dict]:
|
||||||
processed = []
|
processed = []
|
||||||
order = {'critical': 0, 'high': 1, 'medium': 2, 'low': 3}
|
order = {'critical': 0, 'high': 1, 'medium': 2, 'low': 3}
|
||||||
sorted_issues = sorted(issues, key=lambda x: order.get(x.get('severity', 'low'), 4))
|
sorted_issues = sorted(issues, key=lambda x: order.get(x.get('severity', 'low'), 4))
|
||||||
|
|
||||||
sev_labels = {
|
sev_labels = {
|
||||||
'critical': 'CRITICAL',
|
'critical': 'CRITICAL',
|
||||||
'high': 'HIGH',
|
'high': 'HIGH',
|
||||||
'medium': 'MEDIUM',
|
'medium': 'MEDIUM',
|
||||||
'low': 'LOW'
|
'low': 'LOW'
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in sorted_issues:
|
for i in sorted_issues:
|
||||||
item = i.copy()
|
item = i.copy()
|
||||||
item['severity'] = item.get('severity', 'low')
|
item['severity'] = item.get('severity', 'low')
|
||||||
|
|
@ -420,18 +428,24 @@ class ReportGenerator:
|
||||||
code = item.get('code_snippet') or item.get('code') or item.get('context')
|
code = item.get('code_snippet') or item.get('code') or item.get('context')
|
||||||
if isinstance(code, list):
|
if isinstance(code, list):
|
||||||
code = '\n'.join(code)
|
code = '\n'.join(code)
|
||||||
item['code_snippet'] = code if code else None
|
item['code_snippet'] = cls._escape_html(code) if code else None
|
||||||
|
|
||||||
# 确保 description 不为 None
|
# 确保 description 不为 None
|
||||||
desc = item.get('description')
|
desc = item.get('description')
|
||||||
if not desc or desc == 'None':
|
if not desc or desc == 'None':
|
||||||
desc = item.get('title', '') # 如果没有描述,使用标题
|
desc = item.get('title', '') # 如果没有描述,使用标题
|
||||||
item['description'] = desc
|
item['description'] = cls._escape_html(desc)
|
||||||
|
|
||||||
# 确保 suggestion 不为 None
|
# 确保 suggestion 不为 None
|
||||||
suggestion = item.get('suggestion')
|
suggestion = item.get('suggestion')
|
||||||
if suggestion == 'None' or suggestion is None:
|
if suggestion == 'None' or suggestion is None:
|
||||||
item['suggestion'] = None
|
item['suggestion'] = None
|
||||||
|
else:
|
||||||
|
item['suggestion'] = cls._escape_html(suggestion)
|
||||||
|
|
||||||
|
# 转义标题和文件路径
|
||||||
|
item['title'] = cls._escape_html(item.get('title', ''))
|
||||||
|
item['file_path'] = cls._escape_html(item.get('file_path'))
|
||||||
|
|
||||||
processed.append(item)
|
processed.append(item)
|
||||||
return processed
|
return processed
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue