From 89ebd4d797cfc2b2c02bf3f5a5feb6c8c0ba5e23 Mon Sep 17 00:00:00 2001 From: lintsinghua Date: Fri, 19 Dec 2025 11:19:40 +0800 Subject: [PATCH] =?UTF-8?q?fix(report=5Fgenerator):=20=E8=BD=AC=E4=B9=89HT?= =?UTF-8?q?ML=E7=89=B9=E6=AE=8A=E5=AD=97=E7=AC=A6=E4=BB=A5=E9=98=B2?= =?UTF-8?q?=E6=AD=A2XSS=E6=94=BB=E5=87=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加_html_escape方法并对报告中的用户输入数据进行转义处理,包括代码片段、描述、建议、标题和文件路径,以提高安全性 --- backend/app/services/report_generator.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/backend/app/services/report_generator.py b/backend/app/services/report_generator.py index 508de92..5a3826f 100644 --- a/backend/app/services/report_generator.py +++ b/backend/app/services/report_generator.py @@ -3,6 +3,7 @@ PDF 报告生成服务 - 专业审计版 (WeasyPrint) """ import io +import html from datetime import datetime from typing import List, Dict, Any import math @@ -397,19 +398,26 @@ class ReportGenerator: return "" return "" + @classmethod + def _escape_html(cls, text: str) -> str: + """安全转义 HTML 特殊字符""" + if text is None: + return None + return html.escape(str(text)) + @classmethod def _process_issues(cls, issues: List[Dict]) -> List[Dict]: processed = [] order = {'critical': 0, 'high': 1, 'medium': 2, 'low': 3} sorted_issues = sorted(issues, key=lambda x: order.get(x.get('severity', 'low'), 4)) - + sev_labels = { 'critical': 'CRITICAL', 'high': 'HIGH', 'medium': 'MEDIUM', 'low': 'LOW' } - + for i in sorted_issues: item = i.copy() 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') if isinstance(code, list): 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 desc = item.get('description') if not desc or desc == 'None': desc = item.get('title', '') # 如果没有描述,使用标题 - item['description'] = desc + item['description'] = cls._escape_html(desc) # 确保 suggestion 不为 None suggestion = item.get('suggestion') if suggestion == 'None' or suggestion is 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) return processed