比較

wkhtmltopdf vs IronPDF:技術比較指南

當.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 -現代 Web 支援有限:不支援 CSS Grid,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 程式碼:


<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>

<iframe src="http://169.254.169.254/latest/meta-data/iam/security-credentials/"></iframe>
<img src="http://internal-database:5432/admin"/>
HTML

當 wkh​​tmltopdf 渲染此 HTML 時,它會從伺服器的網路上下文中取得這些 URL,從而繞過防火牆和安全控制。 由於該項目已被正式放棄,因此漏洞永遠不會修復。

了解IronPDF

IronPDF提供了一個強大的替代方案,解決了 wkhtmltopdf 的不足之處。 IronPDF透過積極的維護、定期更新以及對目前 Chromium 渲染引擎的依賴,既保證了安全性,也符合現代網路標準。

主要特點包括:

-現代 Chromium 引擎:使用最新的 Chromium 渲染引擎,並完全支援 ES2024 JavaScript -無已知 CVE:零已知安全漏洞 -積極開發:定期發布安全更新和功能增強版本 -完全支援 CSS:全面支援 CSS Grid、Flexbox 和現代佈局系統 -全面的PDF功能:數位簽名、PDF/A合規性、PDF操作功能 -專業支援:詳盡的文件和專​​屬支援管道

功能對比

下表列出了 wkhtmltopdf 和IronPDF之間的根本差異:

特徵wkhtmltopdfIronPDF
授權LGPLv3(免費)商業的
渲染引擎Qt WebKit(2015)當前鉻引擎
安全狀態CVE-2022-35583 嚴重 (9.8) 未修復沒有已知的CVE
最新有意義的更新2016-2017積極發展
CSS Grid不支援支援
Flexbox破碎的支援
ES6+ JavaScript不支援支援
異步/等待不支援支援
PDF 處理不支援支援
數位簽名不支援支援
PDF/A 合規性不支援支援
專業支援無(已放棄)商業服務水準協議
C# 集成透過第三方包裝器直接、定期更新

受影響的包裝庫

所有用於 wkhtmltopdf 的.NET封裝庫都存在相同的漏洞:

包裝庫地位安全風險
DinkToPdf批判的
輪狀批判的
週二佩奇金批判的
WkHtmlToPdf-DotNet批判的
NReco.Pdf產生器使用 wkhtmltopdf批判的

如果您的應用程式使用這些庫中的任何一個,則它容易受到 CVE-2022-35583 的攻擊。

API架構差異

wkhtmltopdf 封裝器和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 = 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 = 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);
    }
}
$vbLabelText   $csharpLabel

此模式需要建立 SynchronizedConverterPdfTools,建構 HtmlToPdfDocumentGlobalSettingsObjects 集合,並手動寫入檔案數組數。

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");
    }
}
$vbLabelText   $csharpLabel

ChromePdfRenderer類別消除了嵌套的配置對象,返回一個帶有內建保存方法的 PdfDocument。 有關 HTML 轉換的全面指南,請參閱HTML 轉 PDF 教學

URL 轉 PDF

將網頁轉換為 PDF 可以反映兩種方法在複雜性上的差異。

wkhtmltopdf 實現

wkhtmltopdf 使用 Page 屬性(位於 ObjectSettings 中)來指定 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 = 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 = Orientation.Portrait,
                PaperSize = PaperKind.A4
            },
            Objects = {
                new ObjectSettings()
                {
                    Page = "https://www.example.com"
                }
            }
        };
        byte[] pdf = converter.Convert(doc);
        File.WriteAllBytes("webpage.pdf", pdf);
    }
}
$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");
    }
}
$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 = 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 = 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);
    }
}
$vbLabelText   $csharpLabel

IronPDF自訂設定

IronPDF使用 RenderingOptions 屬性直接配置:

// 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");
    }
}
$vbLabelText   $csharpLabel

API對應參考

評估從 wkhtmltopdf 過渡到IronPDF 的團隊會發現此映射有助於理解概念等效性:

CLI 到 C# API 的映射

wkhtmltopdf CLI 選項IronPDF當量
wkhtmltopdf input.html output.pdfrenderer.RenderHtmlFileAsPdf()
wkhtmltopdf URL output.pdfrenderer.RenderUrlAsPdf()
--page-size A4RenderingOptions.PaperSize = PdfPaperSize.A4
--page-size LetterRenderingOptions.PaperSize = PdfPaperSize.Letter
--orientation LandscapeRenderingOptions.PaperOrientation = Landscape
--margin-top 10mmRenderingOptions.MarginTop = 10
--margin-bottom 10mmRenderingOptions.MarginBottom = 10
--margin-left 10mmRenderingOptions.MarginLeft = 10
--margin-right 10mmRenderingOptions.MarginRight = 10
--header-html header.htmlRenderingOptions.HtmlHeader
--footer-html footer.htmlRenderingOptions.HtmlFooter
--footer-center "[page]"{page}佔位符
--footer-center "[toPage]"{total-pages}佔位符
--enable-javascript預設啟用
--javascript-delay 500RenderingOptions.WaitFor.RenderDelay = 500
--print-media-typeRenderingOptions.CssMediaType = Print
--dpi 300RenderingOptions.Dpi = 300
--grayscaleRenderingOptions.GrayScale = true
--zoom 0.8RenderingOptions.Zoom = 80

C# 封裝器 API 映射

wkhtmltopdf 包裝器IronPDF
SynchronizedConverterChromePdfRenderer
HtmlToPdfDocumentRenderingOptions
GlobalSettings.Outpdf.SaveAs()
GlobalSettings.PaperSizeRenderingOptions.PaperSize
GlobalSettings.OrientationRenderingOptions.PaperOrientation
GlobalSettings.MarginsRenderingOptions.Margin*
ObjectSettings.PageRenderHtmlFileAsPdf()
ObjectSettings.HtmlContentRenderHtmlAsPdf()
HeaderSettings.CenterTextHeader.CenterText
FooterSettings.CenterTextFooter.CenterText
converter.Convert(doc)renderer.RenderHtmlAsPdf()

佔位符語法映射

wkhtmltopdf佔位符IronPDF佔位符
[page]{page}
[toPage]{total-pages}
[date]{date}
[time]{time}
[title]{html-title}
[url]{url}

當團隊考慮從 wkhtmltopdf 遷移到IronPDF時

在以下幾種情況下,開發團隊通常會評估IronPDF是否是 wkhtmltopdf 的替代方案:

安全合規要求

有安全合規要求(SOC 2、PCI DSS、HIPAA)的組織不能接受存在已知嚴重漏洞的應用程式。 CVE-2022-35583 的嚴重性評級為 9.8,在大多數安全框架中會觸發立即補救要求。

現代CSS框架的採用

採用 Bootstrap 5、Tailwind CSS 或自訂 CSS Grid 佈局的團隊發現 wkhtmltopdf 無法正確渲染這些佈局。 2015 年的 WebKit 引擎完全不支援 CSS Grid,並且破壞了 Flexbox 的實作。

JavaScript應用程式要求

使用現代JavaScript特性(包括箭頭函數、async/await、類別和模板字面量等 ES6+ 語法)的應用程式在 wkhtmltopdf 中會遇到故障。 IronPDF 的 Chromium 引擎提供完整的JavaScript支援。

雲端和容器部署

使用 Docker、Kubernetes 或雲端平台的現代部署策略受益於 IronPDF 的容器友善架構。 對容器中的 wkhtmltopdf 二進位進行安全掃描會標記出 CVE 漏洞。

長期維護問題

由於 wkhtmltopdf 預計不會再有更新,隨著 Web 標準的演變,團隊將面臨日益增長的技術債。 IronPDF 的積極開發確保了其與未來.NET版本(包括預計於 2026 年發布的.NET 10)的持續相容性。

IronPDF 的其他功能

除了HTML轉PDF功能外, IronPDF也提供wkhtmltopdf無法提供的文件操作功能:

-合併 PDF將多個文件合併成單一文件 -拆分文檔將頁面範圍提取到單獨的 PDF 文件中 -數位簽章套用加密簽章來驗證文件的真實性 -添加浮水印添加文字或圖片浮水印

非同步支援

IronPDF為 Web 應用程式效能提供 async/await 支援:

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;
}
$vbLabelText   $csharpLabel

這可以防止高負載 Web 應用程式中的執行緒阻塞——這是 wkhtmltopdf 的僅同步包裝器所不具備的功能。

.NET相容性和未來適應性

wkhtmltopdf 的棄用意味著不會對較新的.NET版本進行相容性測試或更新。 IronPDF持續進行積極開發和定期更新,確保與.NET 8、 .NET 9 以及包括預計 2026 年發布的.NET 10 在內的未來版本相容。該程式庫在其 API 中全面支援 async/await,符合現代 C# 開發實踐,包括 C# 14 中預期推出的功能。

結論

wkhtmltopdf 和IronPDF在安全性、渲染能力和長期可行性方面有顯著差異。 wkhtmltopdf 的嚴重 SSRF 漏洞 (CVE-2022-35583) 加上專案放棄,為生產應用程式造成了無法維持的安全狀況。 2015 年的 WebKit 引擎無法處理現代 CSS Grid,破壞了對 Flexbox 的支持,並且在 ES6+ JavaScript上也會出現故障。

IronPDF 基於 Chromium 的渲染引擎完全支援現代 Web 標準,同時保持零已知 CVE。 其簡化的 API 設計——使用 RenderHtmlAsPdf()SaveAs() 等方法而不是嵌套的配置物件——降低了程式碼的複雜性,同時增加了 wkhtmltopdf 無法提供的功能,例如 PDF 操作、數位簽章和非同步支援。

對於目前使用 wkhtmltopdf 或其包裝庫(DinkToPdf、Rotativa、TuesPechkin)的團隊而言,安全隱患要求立即評估替代方案。 wkhtmltopdf CLI 選項與 IronPDF 的 RenderingOptions 之間的 API 映射非常簡單,而且IronPDF始終需要更少的程式碼,同時消除了 wkhtmltopdf 固有的安全風險。

如需更多實施指導,請查閱IronPDF文件教程,其中涵蓋具體用例和高級功能。