比較

SAP Crystal Reports與IronPDF:技術比較指南

當.NET開發人員需要將HTML轉換為PDF時,由於wkhtmltopdf是開源且指令行簡單,歷來是一個熱門選擇。 然而,項目的終止和嚴重的安全漏洞促使許多團隊評估現代替代方案。 這項技術比較考察了wkhtmltopdf和IronPDF,以幫助架構師和開發人員了解在安全姿態、渲染能力和長期可行性方面的重要差異。

了解wkhtmltopdf

wkhtmltopdf是一個從指令行運行並利用Qt WebKit處理HTML內容,將HTML轉換為PDF文件的工具。 在其活躍的開發年期間,由於免費的LGPLv3許可和跨平台可用性,該程式庫廣受歡迎。

然而,wkhtmltopdf現在提出了不可忽視的關鍵挑戰:

  • 項目終止:最後有意義的軟體更新約在2016-2017年間發生。
  • 嚴重安全漏洞: CVE-2022-35583(CVSS 9.8嚴重性)是一個未修補的SSRF漏洞。
  • 過時的渲染引擎:依賴2015年的Qt WebKit。
  • 有限的現代網頁支援:沒有CSS Grid支持,無法運行Flexbox實現,沒有ES6+ JavaScript支援。
  • 生態系統停滯:所有.NET包裝程式庫(DinkToPdf,Rotativa,TuesPechkin,wkhtmltopdf-.NET,NReco.PdfGenerator)均繼承這些漏洞。

CVE-2022-35583安全危機

wkhtmltopdf中的伺服器端請求偽造(SSRF)漏洞允許攻擊者:

  • 存取內部服務:到達防火牆後面的內部API、資料庫和服務。
  • 竊取憑證:存取雲端元資料端點(AWS、GCP、Azure)以竊取IAM憑證。
  • 端口掃描:從基礎結構內部掃描內部網路。
  • 資料滲漏:通過精心製作的HTML/CSS提取敏感資料。

攻擊向量是直截了當的—惡意HTML提交給PDF生成器:


<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

當wkhtmltopdf渲染此HTML時,它會從伺服器的網路上下文中獲取這些URL,繞過防火牆和安全控件。 由於該項目已被正式終止,此漏洞永遠不會被修補。

了解IronPDF

IronPDF提供了一個解決wkhtmltopdf缺陷的強大替代方案。 通過積極維護、定期更新以及依賴當前的Chromium渲染引擎,IronPDF提供了安全性和現代網頁標準的合規性。

關鍵特性包括:

  • 現代Chromium引擎:使用當前的Chromium渲染引擎,完全支援ES2024 JavaScript。
  • 無已知CVE:無已知安全漏洞。
  • 積極開發:定期發布安全更新和功能增強。
  • 完整CSS支持:完整支持CSS Grid、Flexbox和現代佈局系統。
  • 全面的PDF功能:數位簽名、PDF/A合規、PDF操作能力。
  • 專業支持:廣泛的文件和專門的支持渠道。

功能比較

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

功能wkhtmltopdfIronPDF
授權LGPLv3(免費)商業
渲染引擎Qt WebKit(2015)當前Chromium引擎
安全狀況CVE-2022-35583 嚴重(9.8)未修補無已知CVE
最後有意義的更新2016-2017積極開發中
 CSS Grid不支持支持
 Flexbox故障支持
ES6+ JavaScript不支持支持
Async/Await不支持支持
PDF 操作不支持支持
數位簽名不支持支持
PDF/A合規性不支持支持
專業支持無(已終止)商業服務協議
C#整合通過第三方包裝直接,定期更新

受影響的包裝程式庫

所有針對wkhtmltopdf的.NET包裝均繼承相同的漏洞:

包裝程式庫狀態安全風險
DinkToPdf已廢棄CRITICAL(嚴重)
Rotativa已廢棄CRITICAL(嚴重)
TuesPechkin已廢棄CRITICAL(嚴重)
wkhtmltopdf-.NET已廢棄CRITICAL(嚴重)
NReco.PdfGenerator使用wkhtmltopdfCRITICAL(嚴重)

如果您的應用程式使用這些程式庫中的任何一個,它將容易受到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);
    }
}
' NuGet: Install-Package WkHtmlToPdf-DotNet
Imports WkHtmlToPdfDotNet
Imports WkHtmlToPdfDotNet.Contracts
Imports System.IO

Class Program
    Shared Sub Main()
        Dim converter = New SynchronizedConverter(New PdfTools())
        Dim doc = New HtmlToPdfDocument() With {
            .GlobalSettings = New GlobalSettings() With {
                .ColorMode = ColorMode.Color,
                .Orientation = Orientation.Portrait,
                .PaperSize = PaperKind.A4
            },
            .Objects = {
                New ObjectSettings() With {
                    .HtmlContent = "<h1>Hello World</h1><p>This is a PDF from HTML.</p>"
                }
            }
        }
        Dim pdf As Byte() = converter.Convert(doc)
        File.WriteAllBytes("output.pdf", pdf)
    End Sub
End Class
$vbLabelText   $csharpLabel

此模式需要使用GlobalSettingsObjects集合,並將位元組陣列手動寫入文件。

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");
    }
}
Imports IronPdf
Imports System

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF from HTML.</p>")
        pdf.SaveAs("output.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

ChromePdfRenderer類消除了巢狀配置物件,返回一個具有內建保存方法的PdfDocument。 有關全面的HTML轉換指導,請參見HTML轉PDF教程

URL 轉 PDF

將網頁轉換為PDF展示了這些方法之間的複雜性差異。

wkhtmltopdf實施

wkhtmltopdf在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 = 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);
    }
}
' NuGet: Install-Package WkHtmlToPdf-DotNet
Imports WkHtmlToPdfDotNet
Imports WkHtmlToPdfDotNet.Contracts
Imports System.IO

Module Program
    Sub Main()
        Dim converter As New SynchronizedConverter(New PdfTools())
        Dim doc As New HtmlToPdfDocument() With {
            .GlobalSettings = New GlobalSettings() With {
                .ColorMode = ColorMode.Color,
                .Orientation = Orientation.Portrait,
                .PaperSize = PaperKind.A4
            },
            .Objects = {
                New ObjectSettings() With {
                    .Page = "https://www.example.com"
                }
            }
        }
        Dim pdf As Byte() = converter.Convert(doc)
        File.WriteAllBytes("webpage.pdf", pdf)
    End Sub
End Module
$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");
    }
}
Imports IronPdf
Imports System

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
        pdf.SaveAs("webpage.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

RenderUrlAsPdf方法利用Chromium引擎渲染頁面,完整執行JavaScript並支持現代CSS——這是wkhtmltopdf的2015 WebKit引擎所限制的能力。

自定義PDF設置

配置頁面尺寸、邊距和方向揭示了API之間的結構差異。

wkhtmltopdf自定義設置

wkhtmltopdf需要巢狀的MarginSettings物件:

// 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);
    }
}
' NuGet: Install-Package WkHtmlToPdf-DotNet
Imports WkHtmlToPdfDotNet
Imports WkHtmlToPdfDotNet.Contracts
Imports System.IO

Class Program
    Shared Sub Main()
        Dim converter As New SynchronizedConverter(New PdfTools())
        Dim doc As New HtmlToPdfDocument() With {
            .GlobalSettings = New GlobalSettings() With {
                .ColorMode = ColorMode.Color,
                .Orientation = Orientation.Landscape,
                .PaperSize = PaperKind.A4,
                .Margins = New MarginSettings() With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}
            },
            .Objects = {
                New ObjectSettings() With {
                    .Page = "input.html",
                    .WebSettings = New WebSettings() With {.DefaultEncoding = "utf-8"}
                }
            }
        }
        Dim pdf As Byte() = converter.Convert(doc)
        File.WriteAllBytes("custom-output.pdf", pdf)
    End Sub
End Class
$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");
    }
}
Imports IronPdf
Imports IronPdf.Rendering
Imports System

Class Program
    Shared Sub Main()
        Dim renderer As 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

        Dim pdf = renderer.RenderHtmlFileAsPdf("input.html")
        pdf.SaveAs("custom-output.pdf")
    End Sub
End Class
$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提供未來更新,隨著網頁標準的演變,團隊面臨日益增長的技術債務。 IronPDF的主動開發確保與未來.NET版本的持續相容性,包括預計於2026年發布的.NET 10。

IronPDF的額外功能

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

異步支持

IronPDF針對網頁應用程式的性能提供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;
}
Imports System.Threading.Tasks

Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
    Dim renderer As New ChromePdfRenderer()
    Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
    Return pdf.BinaryData
End Function
$vbLabelText   $csharpLabel

這可以防止在高負荷的網頁應用程式中堵住執行緒——這是一個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的渲染引擎提供了對現代網頁標準的完整支持,同時保持零已知CVE。 其簡化的API設計——例如使用SaveAs()替代巢狀配置物件——減少了程式碼複雜性,同時增加了例如PDF操作、數位簽名和異步支持等能力,這是wkhtmltopdf無法提供的。

對於當前使用wkhtmltopdf或其包裝程式庫(DinkToPdf、Rotativa、TuesPechkin)的團隊,安全影響要求立即評估替代方案。 wkhtmltopdf CLI選項和IronPDF的RenderingOptions之間的API映射是簡單明瞭的,IronPDF始終需要更少的程式碼,同時消除了wkhtmltopdf固有的安全風險。

如需額外的實施指南,請探索IronPDF文件教程,涵蓋特定用例和高級功能。

請注意DinkToPdf, NReco, Rotativa, TuesPechkin, 和 wkhtmltopdf 是其各自所有者的註冊商標。 本網站與DinkToPdf, NReco, Rotativa, TuesPechkin, 或 wkhtmltopdf無關聯,不受其認可或支持。 所有產品名稱、標誌和品牌均為其各自所有者的財產。 比較僅供資訊參考,並反映了撰寫時公開的資訊。)}