HTML模板JavaScript注入重现与防护方案咨询(PDF转换场景)
重现HTML注入场景与防护方案
一、重现document.write注入影响PDF的场景
- 在前端模板的动态填充区域插入如下注入代码:
<script>document.write('failed');</script> - 用Postman将填充后的完整HTML字符串发送至后端
ConvertHTMLStringToPDFStream接口 - 后端SelectPdf引擎渲染时会执行这段脚本,
document.write会直接改写HTML内容,最终生成的PDF里就会显示failed文本
二、为什么onerror脚本未生效?
SelectPdf的HTML转PDF引擎对JS的支持并非完全模拟浏览器环境:
onerror事件通常需要依赖浏览器的资源加载失败、DOM错误等场景触发,但SelectPdf的渲染流程是同步的,不会主动模拟这类触发条件- 部分异步或事件驱动的JS逻辑,在PDF的静态渲染流程中无法被执行
三、前端Angular防护方案
1. 严格的HTML内容清理
使用Angular内置DomSanitizer配合DOMPurify(直接集成库)过滤危险内容:
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import DOMPurify from 'dompurify'; constructor(private sanitizer: DomSanitizer) {} sanitizeUserInput(input: string): SafeHtml { // 自动过滤script标签、on*属性等危险元素 const cleanHtml = DOMPurify.sanitize(input); return this.sanitizer.bypassSecurityTrustHtml(cleanHtml); }
- 所有用户输入的动态内容,必须经过上述方法处理后,才能绑定到模板的
[innerHTML]上
2. 模板层面限制
禁止在Angular模板中直接绑定未清理的原始HTML,必须使用经过 sanitize 处理后的SafeHtml对象
四、后端.NET(SelectPdf)防护方案
1. 直接禁用JavaScript执行
在转换方法中关闭JS支持,从根源阻止脚本运行:
public Stream ConvertHTMLStringToPDFStream(string htmlContent) { using var converter = new HtmlToPdf(); // 禁用所有JS执行,彻底避免脚本注入风险 converter.Options.JavaScriptEnabled = false; using var doc = converter.ConvertHtmlString(htmlContent); var stream = new MemoryStream(); doc.Save(stream); stream.Position = 0; return stream; }
2. 预处理HTML过滤危险内容
使用HtmlAgilityPack清理HTML中的危险元素:
using HtmlAgilityPack; private string SanitizeHtml(string htmlContent) { var doc = new HtmlDocument(); doc.LoadHtml(htmlContent); // 删除所有script标签 foreach (var scriptNode in doc.DocumentNode.SelectNodes("//script") ?? Enumerable.Empty<HtmlNode>()) { scriptNode.Remove(); } // 移除所有on开头的事件属性 foreach (var node in doc.DocumentNode.SelectNodes("//*[@*[starts-with(name(), 'on')]]") ?? Enumerable.Empty<HtmlNode>()) { var unsafeAttrs = node.Attributes.Where(a => a.Name.StartsWith("on")).ToList(); foreach (var attr in unsafeAttrs) { node.Attributes.Remove(attr); } } return doc.DocumentNode.OuterHtml; }
转换PDF前先调用清理方法:
public Stream ConvertHTMLStringToPDFStream(string htmlContent) { var cleanHtml = SanitizeHtml(htmlContent); using var converter = new HtmlToPdf(); using var doc = converter.ConvertHtmlString(cleanHtml); var stream = new MemoryStream(); doc.Save(stream); stream.Position = 0; return stream; }
3. 限制资源加载权限
通过SelectPdf配置避免脚本触发远程请求:
converter.Options.WebPageLoadTimeout = 5; // 缩短加载超时,避免恶意资源阻塞 converter.Options.AllowRemoteContent = false; // 禁用远程资源加载 converter.Options.AllowLocalContent = true; // 仅允许本地资源(根据业务调整)
内容的提问来源于stack exchange,提问作者bob.mazzo
相关产品推荐
相关产品推荐

