基于Angular与.NET Core的PDF上传防XSS:拒绝含嵌入式JavaScript的文件
如何在Angular+.NET Core应用中拦截含嵌入式JavaScript的PDF文件
要防范PDF中的嵌入式JS引发的XSS攻击,得从客户端初步拦截+服务端严格校验双管齐下,同时配合后续查看环节的防护,以下是具体实现方案:
一、Angular客户端初步校验(辅助,不能替代服务端)
客户端可以提前拦截明显含JS的PDF,减少无效请求。这里用pdf-lib库解析PDF内容:
- 安装依赖:
npm install @pdf-lib/core
- 上传组件中添加校验逻辑:
import { PDFDocument } from '@pdf-lib/core'; // 检查PDF是否包含嵌入式JS async function hasEmbeddedJavaScript(file: File): Promise<boolean> { try { const arrayBuffer = await file.arrayBuffer(); const pdfDoc = await PDFDocument.load(arrayBuffer); // 检查全局JavaScript字典 const rootDict = pdfDoc.context.trailerInfo.get('Root'); const hasGlobalJS = rootDict?.get('Names')?.get('JavaScript') !== undefined; // 检查表单字段的JS动作(比如按钮点击脚本) let hasFieldJS = false; const acroForm = rootDict?.get('AcroForm'); if (acroForm) { const fields = acroForm.get('Fields'); if (fields) { for (const field of fields.array) { const actions = field.get('AA'); if (actions && actions.get('MouseUp')?.get('JS')) { hasFieldJS = true; break; } } } } return hasGlobalJS || hasFieldJS; } catch (err) { // 解析失败的PDF直接判定为可疑 return true; } } // 上传触发逻辑 async function handleUpload(event: Event) { const file = (event.target as HTMLInputElement).files?.[0]; if (!file) return; const isInvalid = await hasEmbeddedJavaScript(file); if (isInvalid) { alert('该PDF包含嵌入式JavaScript,禁止上传'); return; } // 执行正常上传流程 }
二、.NET Core服务端严格校验(核心防护)
客户端校验可被篡改,必须在服务端做最终拦截。推荐用iText7(支持.NET Core的PDF处理库)检测JS:
- 安装NuGet包:
dotnet add package iText7
- 上传接口中添加校验逻辑:
using iText.Kernel.Pdf; public async Task<IActionResult> UploadPdf(IFormFile file) { if (file == null || file.Length == 0) return BadRequest("请选择要上传的文件"); // 校验文件扩展名(辅助,优先检查实际内容) var ext = Path.GetExtension(file.FileName).ToLowerInvariant(); if (ext != ".pdf") return BadRequest("仅支持PDF格式文件"); bool containsJavaScript = false; using (var pdfReader = new PdfReader(file.OpenReadStream())) { using var pdfDoc = new PdfDocument(pdfReader); var catalog = pdfDoc.GetCatalog().GetPdfObject(); // 检查全局JavaScript字典 var namesDict = catalog.GetAsDictionary(PdfName.Names); if (namesDict != null && namesDict.GetAsDictionary(PdfName.JavaScript)?.Size > 0) { containsJavaScript = true; } // 检查表单字段的JS动作 var acroForm = catalog.GetAsDictionary(PdfName.AcroForm); if (acroForm != null) { var fields = acroForm.GetAsArray(PdfName.Fields); if (fields != null) { foreach (PdfObject fieldObj in fields) { var field = (PdfDictionary)fieldObj; var actionDict = field.GetAsDictionary(PdfName.AA); if (actionDict != null) { var mouseUpAction = actionDict.GetAsDictionary(PdfName.MouseUp); if (mouseUpAction != null && mouseUpAction.Get(PdfName.JS) != null) { containsJavaScript = true; break; } } } } } } if (containsJavaScript) return BadRequest("该PDF包含嵌入式JavaScript,禁止上传"); // 执行文件存储等后续逻辑 return Ok("上传成功"); }
三、额外防护措施
存储与分发:
- 上传后的PDF重命名为随机字符串,避免文件名注入风险
- 响应时强制设置
Content-Type: application/pdf,禁止浏览器自动执行未知内容 - 用沙箱化的
<iframe>加载PDF:<iframe src="/files/xxx.pdf" sandbox="allow-same-origin allow-top-navigation"></iframe>
查看环节:
- 使用无JS支持的PDF查看组件,或配置浏览器PDF查看器禁用JavaScript
- 严格控制查看页面的权限,禁止用户执行自定义脚本
内容的提问来源于stack exchange,提问作者Sarahbe
相关产品推荐
相关产品推荐

