如何在.NET Core中检测PDF文档中的JavaScript脚本?
在.NET Core中检测PDF中的JavaScript(无需付费库)
完全可以不用付费库实现这个功能,下面提供几种可行的思路和实现方案:
方案1:简单文本匹配(快速筛查)
PDF的核心结构是文本格式的,JavaScript相关逻辑通常会携带/JS、/JavaScript、/AA(附加动作)或javascript:这类特定标记。我们可以直接读取PDF内容,过滤掉注释(PDF注释以%开头)后检查这些标记。
这种方案优点是实现简单、速度快,适合做初步检测;缺点是可能存在误报(比如文本内容恰好包含这些字符串)。
示例代码:
using System.IO; using System.Text; using System.Linq; public bool HasJavaScriptSimple(string pdfPath) { // PDF默认采用ASCII编码,部分包含特殊字符的可能用UTF-8 var pdfContent = File.ReadAllText(pdfPath, Encoding.ASCII); var jsMarkers = new[] { "/JS", "/JavaScript", "/AA", "javascript:" }; foreach (var line in pdfContent.Split('\n')) { var trimmedLine = line.Trim(); // 跳过PDF注释行 if (trimmedLine.StartsWith("%")) continue; if (jsMarkers.Any(marker => trimmedLine.Contains(marker))) { return true; } } return false; }
方案2:轻量级PDF对象解析(更准确)
PDF由多个对象(格式为[编号] [版本] obj ... endobj)组成,JavaScript通常存储在对象的字典结构中。我们可以通过正则匹配提取所有PDF对象,再在对象内容中查找JS相关标记,排除注释干扰。
这种方案比文本匹配更准确,但需要处理PDF的基本对象结构;如果遇到压缩后的PDF(比如用FlateDecode压缩的对象),还需要额外处理解压逻辑(可以用.NET Core自带的DeflateStream实现)。
示例代码:
using System.IO; using System.Text; using System.Text.RegularExpressions; public bool HasJavaScriptAdvanced(string pdfPath) { var pdfContent = File.ReadAllText(pdfPath, Encoding.ASCII); // 匹配所有PDF对象 var objRegex = new Regex(@"\d+\s+\d+\s+obj(.*?)endobj", RegexOptions.Singleline); var objMatches = objRegex.Matches(pdfContent); foreach (Match match in objMatches) { var objContent = match.Groups[1].Value; foreach (var line in objContent.Split('\n')) { var trimmedLine = line.Trim(); if (trimmedLine.StartsWith("%")) continue; if (trimmedLine.Contains("/JS") || trimmedLine.Contains("/JavaScript")) { return true; } } } return false; }
方案3:使用免费开源PDF库(最可靠)
如果需要更准确、全面的检测,推荐使用iText 7 Community Edition——这是一款免费开源的PDF处理库,完全支持.NET Core,能处理复杂的PDF结构(包括压缩对象、页面动作、表单字段动作等)。
示例代码:
using iText.Kernel.Pdf; using iText.Kernel.Pdf.Action; public bool HasJavaScriptWithItext(string pdfPath) { using var pdfReader = new PdfReader(pdfPath); using var pdfDoc = new PdfDocument(pdfReader); // 检查文档级全局JavaScript if (pdfDoc.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.JavaScript) != null) { return true; } // 检查页面附加动作(如打开/关闭页面时的JS) for (int pageNum = 1; pageNum <= pdfDoc.GetNumberOfPages(); pageNum++) { var page = pdfDoc.GetPage(pageNum); var pageActions = page.GetPdfObject().GetAsDictionary(PdfName.AA); if (pageActions != null && HasJsAction(pageActions)) { return true; } } // 检查表单字段的JavaScript动作 var form = pdfDoc.GetForm(); if (form != null) { foreach (var field in form.GetFields()) { var fieldActions = field.GetPdfObject().GetAsDictionary(PdfName.AA); if (fieldActions != null && HasJsAction(fieldActions)) { return true; } } } return false; } // 辅助方法:检查动作字典中是否包含JS动作 private bool HasJsAction(PdfDictionary actionDict) { foreach (var key in actionDict.KeySet()) { var action = actionDict.GetAsDictionary(key); if (action != null && PdfName.JS.Equals(action.GetAsName(PdfName.S))) { return true; } } return false; }
注意事项
- 如果选择自己解析PDF,需要注意处理压缩对象:PDF中部分对象会用FlateDecode压缩,此时需要先读取压缩的字节流,用
DeflateStream解压后再解析内容。 - iText 7 Community Edition完全免费,可通过NuGet直接安装(包名:
itext7)。
内容的提问来源于stack exchange,提问作者Ilan
相关产品推荐
相关产品推荐

