比较

wkhtmltopdf 与 IronPDF:技术比较指南

wkhtmltopdf与 IronPDF:.NET PDF 生成技术比较

当.NET 开发人员需要将 HTML 转换为 PDF 时,wkhtmltopdf 因其开源性和命令行简易性历来是最受欢迎的选择。 然而,项目的废弃和严重的安全漏洞促使许多团队开始评估现代的替代方案。 本技术比较将对wkhtmltopdf和IronPDF进行研究,以帮助架构师和开发人员了解它们在安全态势、渲染能力和长期可行性方面的显著差异。

了解 wkhtmltopdf.

wkhtmltopdf 是一款将 HTML 转换为 PDF 文档的工具,可直接从命令行运行,并利用 Qt WebKit 处理 HTML 内容。 在多年的积极开发过程中,该库因其免费的 LGPLv3 许可和跨平台可用性而广受欢迎。

然而,wkhtmltopdf 目前面临着不容忽视的严峻挑战:

  • 项目放弃:最后一次有意义的软件更新发生在 2016-2017 年左右
  • 关键安全漏洞:CVE-2022-35583(CVSS 9.8 严重性)是一个仍未修补的 SSRF 漏洞
  • 过时的渲染引擎:依赖于 2015 年的 Qt WebKit
  • 有限的现代网络支持:不支持 CSS 网格、Flexbox 实现被破坏、无 ES6+ JavaScript
  • 生态系统停滞:所有 .NET 封装库(DinkToPdf、Rotativa、TuesPechkin、WkHtmlToPdf-DotNet、NReco.PdfGenerator)都继承了这些漏洞

CVE-2022-35583 安全危机

wkhtmltopdf 中的服务器端请求伪造 (SSRF) 漏洞允许攻击者

  • 访问内部服务:访问防火墙后的内部 API、数据库和服务
  • 窃取凭证:访问云元数据端点(AWS、GCP、Azure)以窃取 IAM 凭据
  • 端口扫描:从基础设施内部扫描内部网络
  • 数据渗透:通过精心制作的 HTML/CSS 提取敏感数据

攻击载体简单明了--向 PDF 生成器提交恶意 HTML:

<!-- Malicious HTML submitted to your PDF generator -->
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>
<!-- Malicious HTML submitted to your PDF generator -->
<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>
HTML

当wkhtmltopdf渲染 HTML 时,它会绕过防火墙和安全控制,从服务器的网络上下文中获取这些 URL。 该漏洞永远不会被修补,因为该项目已被正式放弃。

了解IronPDF

IronPDF 提供了一个强大的替代方案,解决了wkhtmltopdf的不足之处。 IronPDF拥有积极的维护、定期的更新,并依赖于当前的 Chromium 渲染引擎,因此既安全又符合现代网络标准。

主要特点包括

  • 现代 Chromium 引擎:使用当前的 Chromium 渲染引擎,完全支持 ES2024 JavaScript
  • 无已知 CVE:零已知安全漏洞
  • 积极开发:定期发布安全更新和功能增强
  • 全面的 CSS 支持:完整的 CSS 网格、Flexbox 和现代布局系统
  • 全面的 PDF 功能:数字签名、PDF/A 合规性、PDF 操作功能
  • 专业支持:广泛的文档和专业的支持渠道

功能对比

下表强调了wkhtmltopdf和IronPDF之间的基本差异:

特征wkhtmltopdfIronPDF
许可LGPLv3 (免费)商业翻译
渲染引擎Qt WebKit (2015)当前的 Chromium 引擎
安全状态CVE-2022-35583 关键 (9.8) 未打补丁无已知 CVE
最近一次有意义的更新2016-2017积极开发
CSS 网格不支持全面支持
Flexbox破译全面支持
ES6+JavaScript不支持全面支持
同步/等待不支持全面支持
PDF 操作不支持全面支持
数字签名不支持全面支持
PDF/A合规性不支持全面支持
专业支持无(已放弃)有服务水平协议的商业翻译
C#集成通过第三方封装直接、定期更新

受影响的封装库

wkhtmltopdf 的所有 .NET 封装程序都继承了相同的漏洞:

封装库现状安全风险
DinkToPdf放弃关键
Rotativa放弃关键
TuesPechkin放弃关键
WkHtmlToPdf-DotNet放弃关键
NReco.PdfGenerator使用 wkhtmltopdf关键

如果您的应用程序使用了这些库中的任何一个,那么它就存在 CVE-2022-35583 漏洞。

API 架构差异

wkhtmltopdf wrappers 和IronPDF之间的 API 模式显示了在复杂性和可用性方面的显著差异。

wkhtmltopdf配置模式

wkhtmltopdf 封装程序要求创建具有嵌套设置配置的文档对象:

// NuGet: Install-Package WkHtmlToPdf-DotNet
using WkHtmlToPdfDotNet;
using WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
               定位= Orientation.Portrait,
                PaperSize = PaperKind.A4
            },
            Objects = {
                new ObjectSettings()
                {
                    HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("output.pdf", pdf);
    }
}
// NuGet: Install-Package WkHtmlToPdf-DotNet
using WkHtmlToPdfDotNet;
using WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
               定位= Orientation.Portrait,
                PaperSize = PaperKind.A4
            },
            Objects = {
                new ObjectSettings()
                {
                    HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("output.pdf", pdf);
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

这种模式要求使用 PdfTools 创建<代码>同步转换器</代码,使用 GlobalSettingsObjects 集合构建<代码>HtmlToPdfDocument</代码并手动将字节数组写入文件。

IronPDF简化模式

IronPDF 使用<代码>ChromePdfRenderer</代码类来简化方法:

// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>");
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>");
        pdf.SaveAs("output.pdf");
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

ChromePdfRenderer类消除了嵌套的配置对象,返回一个具有内置保存方法的PdfDocument。 有关全面的 HTML 转换指导,请参阅 HTML 转 PDF 教程

将 URL 转换为 PDF.

将网页转换为 PDF 演示了两种方法之间的复杂性差异。

wkhtmltopdf的实现

wkhtmltopdf 使用 ObjectSettings 中的 Page 属性指定 URL:

// NuGet: Install-Package WkHtmlToPdf-DotNet
using WkHtmlToPdfDotNet;
using WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
               定位= Orientation.Portrait,
                PaperSize = PaperKind.A4
            },
            Objects = {
                new ObjectSettings()
                {
                    Page = "https://www.example.com"
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("webpage.pdf", pdf);
    }
}
// NuGet: Install-Package WkHtmlToPdf-DotNet
using WkHtmlToPdfDotNet;
using WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
               定位= Orientation.Portrait,
                PaperSize = PaperKind.A4
            },
            Objects = {
                new ObjectSettings()
                {
                    Page = "https://www.example.com"
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("webpage.pdf", pdf);
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

IronPdf 的实现

IronPDF 提供了专门的 RenderUrlAsPdf 方法:

// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

RenderUrlAsPdf 方法利用 Chromium 引擎来呈现具有完整JavaScript执行功能和现代 CSS 支持功能的页面--这些功能受到wkhtmltopdf的 2015 WebKit 引擎的限制。

自定义 PDF 设置

配置页面尺寸、页边距和方向可以显示 API 之间的结构差异。

wkhtmltopdf自定义设置

wkhtmltopdf 需要嵌套 GlobalSettingsMarginSettings 对象:

// NuGet: Install-Package WkHtmlToPdf-DotNet
using WkHtmlToPdfDotNet;
using WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
               定位= Orientation.Landscape,
                PaperSize = PaperKind.A4,
                Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
            },
            Objects = {
                new ObjectSettings()
                {
                    Page = "input.html",
                    WebSettings = { DefaultEncoding = "utf-8" }
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("custom-output.pdf", pdf);
    }
}
// NuGet: Install-Package WkHtmlToPdf-DotNet
using WkHtmlToPdfDotNet;
using WkHtmlToPdfDotNet.Contracts;
using System.IO;

class Program
{
    static void Main()
    {
        var converter = new SynchronizedConverter(new PdfTools());
        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
               定位= Orientation.Landscape,
                PaperSize = PaperKind.A4,
                Margins = new MarginSettings() { Top = 10, Bottom = 10, Left = 10, Right = 10 }
            },
            Objects = {
                new ObjectSettings()
                {
                    Page = "input.html",
                    WebSettings = { DefaultEncoding = "utf-8" }
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("custom-output.pdf", pdf);
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

IronPDF自定义设置

IronPDF 使用<代码>渲染选项</代码属性进行直接配置:

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;

        var pdf = renderer.RenderHtmlFileAsPdf("input.html");
        pdf.SaveAs("custom-output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;

        var pdf = renderer.RenderHtmlFileAsPdf("input.html");
        pdf.SaveAs("custom-output.pdf");
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

API 映射参考

正在评估从wkhtmltopdf过渡到IronPDF的团队会发现此映射有助于理解概念等同:

CLI 到 C# API 映射

wkhtmltopdf CLI 选项IronPdf 同等产品备注
<代码>wkhtmltopdf input.html output.pdf</ 代码<代码>renderer.RenderHtmlFileAsPdf()</代码文件到 PDF
<代码>wkhtmltopdf URL output.pdf</ 代码<代码>renderer.RenderUrlAsPdf()</代码URL 至 PDF
<代码>--页面大小 A4</代码<代码>RenderingOptions.PaperSize = PdfPaperSize.A4</ 代码纸张大小
<代码>--页面大小 Letter<代码>RenderingOptions.PaperSize = PdfPaperSize.Letter</ 代码美国信函
<代码>--面向景观</代码<代码>RenderingOptions.PaperOrientation = Landscape</代码定位
--margin-top 10mm</ 代码<代码>RenderingOptions.MarginTop = 10</ 代码边距(毫米
--margin-bottom 10mm<代码>RenderingOptions.MarginBottom = 10</ 代码
<代码>--边距左 10 毫米</代码<代码>RenderingOptions.MarginLeft = 10</ 代码
<代码>--右边距 10 毫米</代码<代码>RenderingOptions.MarginRight = 10</ 代码
<代码>--header-html header.html</ 代码<代码>RenderingOptions.HtmlHeader</代码HTML 标题
--footer-html footer.html<代码>RenderingOptions.HtmlFooter</代码HTML 页脚
--footer-center "[page]"{page} 占位符页码
<代码>--footer-center"[toPage]"</代码{total-pages} 占位符总页数
<代码>--enable-javascript</代码默认已启用JavaScript
<代码>--javascript--延迟 500</代码<代码>RenderingOptions.WaitFor.RenderDelay = 500</代码JS 延误
<代码>--打印媒体类型</代码<代码>RenderingOptions.CssMediaType = 打印</代码CSS 媒体
<代码>--dpi 300</代码<代码>RenderingOptions.Dpi=300</代码DPI 设置
<代码>--grayscale</代码RenderingOptions.GrayScale = true<br灰度
<代码>--zoom 0.8</代码<代码>RenderingOptions.Zoom = 80</ 代码放大 (%)

C# Wrapper API 映射

wkhtmltopdf 封装程序IronPDF备注
<代码>同步转换器</代码<代码>ChromePdfRenderer</代码主呈现器
<代码>HtmlToPdfDocument</代码<代码>渲染选项</代码配置
<代码>GlobalSettings.Out</代码<代码>pdf.SaveAs()</代码输出文件
<代码>GlobalSettings.PaperSize</代码<代码>RenderingOptions.PaperSize</代码纸张大小
<代码>GlobalSettings.Orientation</代码<代码>RenderingOptions.PaperOrientation</代码定位
<代码>GlobalSettings.Margins</代码<代码>RenderingOptions.Margin*</代码个别页边距
<代码>对象设置.页面</代码<代码>RenderHtmlFileAsPdf()</代码文件输入
<代码>ObjectSettings.HtmlContent</代码<代码>RenderHtmlAsPdf()</代码HTML 字符串
<代码>HeaderSettings.Center</代码<代码>TextHeader.CenterText</代码标题文本
<代码>FooterSettings.Center</代码<代码>TextFooter.CenterText</代码页脚文本
<代码>converter.Convert(doc)</代码<代码>renderer.RenderHtmlAsPdf()</代码生成 PDF

占位符语法映射

wkhtmltopdf 占位符IronPdf 占位符
<代码>[页面]</代码{page}
<代码>[toPage]</代码<代码>{总页数}</代码
<代码>[日期]</代码<代码>{日期}</代码
<代码>[时间]</代码<代码>{时间}</代码
<代码>[标题]</代码<代码>{html-title}</代码
<代码>[url]</代码<代码>{url}</代码

团队何时考虑从wkhtmltopdf迁移到 IronPDF?

有几种情况通常会促使开发团队将IronPDF作为wkhtmltopdf的替代品进行评估:

安全合规要求

有安全合规要求(SOC 2、PCI DSS、HIPAA)的组织不能接受存在已知关键漏洞的应用程序。 CVE-2022-35583 的严重性等级为 9.8,在大多数安全框架中都会触发立即修复的要求。

现代 CSS 框架的采用

采用 Bootstrap 5、Tailwind CSS 或自定义 CSS 网格布局的团队会发现wkhtmltopdf无法正确呈现这些布局。 2015 WebKit 引擎完全不支持 CSS 网格,并且破坏了 Flexbox 的实现。

JavaScript应用程序要求

使用现代JavaScript功能(ES6+ 语法,包括箭头函数、async/await、类和模板字面)的应用程序会在wkhtmltopdf中遇到故障。IronPDF的 Chromium 引擎提供完整的JavaScript支持。

云和容器部署

使用 Docker、Kubernetes 或云平台的现代部署策略受益于 IronPdf 的容器友好架构。 容器中wkhtmltopdf二进制文件的安全扫描将标记 CVE 漏洞。

长期维护问题

由于wkhtmltopdf今后预计不会更新,因此随着网络标准的发展,团队将面临越来越多的技术债务。IronPDF的积极开发确保了与未来 .NET 版本的持续兼容性,包括预计在 2026 年推出的 .NET 10。

IronPDF的其他功能

除了 HTML 到 PDF 的转换,IronPDF 还提供wkhtmltopdf无法提供的文档操作功能:

同步支持

IronPdf 为网络应用程序性能提供异步/等待支持:

public async Task<byte[]> GeneratePdfAsync(string html)
{
    var renderer = new ChromePdfRenderer();
    var pdf = await renderer.RenderHtmlAsPdfAsync(html);
    return pdf.BinaryData;
}
public async Task<byte[]> GeneratePdfAsync(string html)
{
    var renderer = new ChromePdfRenderer();
    var pdf = await renderer.RenderHtmlAsPdfAsync(html);
    return pdf.BinaryData;
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

wkhtmltopdf 的同步封装器可以防止高负载网络应用程序中的线程阻塞--这是wkhtmltopdf仅同步封装器不具备的功能。

.NET兼容性和未来准备情况

弃用wkhtmltopdf意味着无法进行兼容性测试或更新较新的 .NET 版本。IronPDFfor .NET 保持着定期更新的积极开发态势,确保与 .NET 8、.NET 9 和未来版本(包括预计于 2026 年发布的 .NET 10)的兼容性。该库的整个 API 均支持 async/await,符合现代 C# 开发实践,包括 C# 14 中的预期功能。

结论

wkhtmltopdf 和IronPDF在安全性、渲染能力和长期可行性方面存在显著差异。wkhtmltopdf的关键 SSRF 漏洞 (CVE-2022-35583) 与项目放弃相结合,为生产应用程序带来了难以承受的安全态势。 2015 WebKit 引擎无法处理现代 CSS 网格,对 Flexbox 的支持已被破坏,并且无法支持 ES6+ JavaScript。

IronPDF 基于 Chromium 的渲染引擎完全支持现代网络标准,同时保持零已知 CVE。 其简化的 API 设计--方法如<代码>RenderHtmlAsPdf()</代码和 SaveAs() 而不是嵌套的配置对象--降低了代码的复杂性,同时增加了wkhtmltopdf无法提供的功能,如 PDF 操作、数字签名和异步支持。

对于目前正在使用wkhtmltopdf或其封装库(DinkToPdf、Rotativa、TuesPechkin)的团队来说,安全问题需要立即评估替代方案。wkhtmltopdfCLI 选项与IronPDF的 RenderingOptions 之间的 API 映射简单明了,IronPDF 始终需要较少的代码,同时消除了wkhtmltopdf固有的安全风险。

有关更多实施指导,请浏览 IronPDF 文档和涵盖特定用例和高级功能的 教程