在 C# 中以编程方式签署 PDF;.NET 10:数字签名指南

This article was translated from English: Does it need improvement?
Translated
View the article in English

C# .NET 中的数字签名通过基于 X.509 证书的加密技术验证 PDF 文档,提供篡改检测、不可抵赖性和长期有效性,而这些仅靠可视签名图像是无法实现的。 IronPDF for .NET 使 .NET 开发人员能够以编程方式直接签名验证保护 PDFs,涵盖从基本证书签名和可视化签名渲染到多方审批工作流、时间戳服务器集成以及与 eIDAS 和 ESIGN 法案 等框架的合规性等各个方面。

as-heading:2(TL;DR:快速入门指南)

本教程包括使用 C# 中的 X.509 证书对 PDF 文档进行编程签名、验证和保护,从单个签名到多方批准链。

  • 适用对象:在合同管理、发票处理或合规系统中构建文档签名功能的 .NET 开发人员。
  • 您将构建的内容:基于证书的 PDF 签名.pfx/.p12)、可视化签名覆盖、多方顺序工作流、签名验证、篡改检测和权限控制文档锁定。
  • 运行环境: .NET 10、.NET 8 LTS、.NET 框架 4.6.2+ 和 .NET Standard 2.0。
  • 何时使用此方法:当您需要大规模地以编程方式签署 PDF 文件而无需通过第三方签署门户进行路由时。
  • 技术原因:加密签名可提供可视签名图像无法提供的篡改证据、不可抵赖性和长期有效性。

要跟上本教程中的代码示例,请查看快速安装指南,在您的项目中设置好 IronPdf。 只需几行代码,即可签署您的第一份 PDF:

Nuget Icon立即开始使用 NuGet 创建 PDF 文件:

  1. 使用 NuGet 包管理器安装 IronPDF

    PM > Install-Package IronPdf

  2. 复制并运行这段代码。

    var signature = new IronPdf.Signing.PdfSignature("certificate.pfx", "password");
    IronPdf.PdfDocument.FromFile("document.pdf").Sign(signature).SaveAs("signed.pdf");
  3. 部署到您的生产环境中进行测试

    立即开始在您的项目中使用 IronPDF,免费试用!
    arrow pointer

下载完整项目

要快速入门,下载本教程中包含所有代码示例的完整工作项目。

下载内容包括一个配置完整的 .NET 项目,其中包含证书示例和所有签名示例,可随时构建和运行。

购买或注册 IronPDF 30 天试用版后,请在应用程序的开头添加许可证密钥。

IronPdf.License.LicenseKey = "KEY";
IronPdf.License.LicenseKey = "KEY";
Imports IronPdf

IronPdf.License.LicenseKey = "KEY"
$vbLabelText   $csharpLabel

今天在您的项目中使用 IronPDF,免费试用。

第一步:
green arrow pointer
NuGet 使用 NuGet 安装

PM >  Install-Package IronPdf

IronPDF 上查看 NuGet 快速安装。超过 1000 万次下载,它正以 C# 改变 PDF 开发。 您也可以下载 DLLWindows 安装程序

as-heading:2(目录)


PDF 文档中的数字签名和可视签名有什么区别?

人们经常交替使用 "数字签名 "和 "电子签名",但它们在文档安全方面的作用却截然不同。 数字签名使用加密技术,用私钥对文档内容的哈希值进行加密。 然后,任何可以访问相应公钥的人都可以验证该文档在签署后没有更改。

另一方面,视觉签名只是在 PDF 页面上放置一张图片。 可以是扫描的手写签名、公司徽标或名称的样式化文本版本。 虽然可视化签名有助于文档在人类读者面前看起来 "有签名",但它们并不提供防止篡改的加密保护。

在实际工作中,业务应用程序往往需要这两种语言的配合使用。 一份法律合同可能需要基于证书的数字签名的加密保护,以确保文件的完整性,Plus 还需要一个可见的签名块,以便收件人可以看到签名人和签名时间。

下表总结了这些签名类型之间的主要区别:

特点 数字签名 视觉签名
加密保护 使用 PKI 和 X.509 证书创建防篡改印章 无,可删除或替换图片
不否认 签署人不能以可信的方式否认签署 不提供技术身份证明
篡改检测 任何修改都将导致签名无效 无法检测文档是否被篡改
法律地位 获得 ESIGN 法案和 eIDAS 等法规的认可 仅可满足 "签署意向 "要求
验证 可通过程序或 PDF 阅读器进行验证 仅需目测
所需证书 是,需要 .pfx 或 .p12 证书文件 不,任何图像文件都可以

对于大多数业务用例而言,数字签名和相应的可视化表示法是安全性和可用性的最佳组合。 加密层确保文档的完整性,而视觉层则为接收者提供熟悉的签名体验。


开发团队如何建立数字签名基础架构?

实施数字签名需要两样东西:用于签名的 X.509 证书和一些关于证书管理在生产中如何运作的知识。 本节将介绍每个组成部分。

IronPDF 的 PDF 签名支持哪些证书格式?

数字签名依赖于 X.509 证书,其中包含一对公钥和私钥以及证书持有者的身份信息。 这些证书的有效期通常为一至三年。 IronPdf 可使用标准 PKCS#12 格式的证书,通常存储为 .pfx.p12 文件。 这些文件将私钥(签名所需的)与公共证书(验证所需的)捆绑到一个受密码保护的容器中。

企业环境通常从以下几个来源之一获得证书:

商业证书颁发机构(如 DigiCert、Sectigo 或 GlobalSign)颁发的证书会自动受到主要 PDF 阅读器的信任。

内部 PKI 基础架构允许组织签发自己的证书,但收件人可能需要手动信任签发 CA。

自签名证书可用于原型开发,但除非手动信任,否则会在 PDF 阅读器中显示警告。

为 IronPdf 加载证书时,必须指定 X509KeyStorageFlags.Exportable 标志。 这可以让加密子系统访问用于签名的私钥。 以下是如何正确加载证书:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/load-certificate.cs
using System.Security.Cryptography.X509Certificates;

// Load the certificate from a PKCS#12 file (.pfx or .p12)
// The Exportable flag allows the private key to be used for signing
var certificate = new X509Certificate2(
    "company-signing-cert.pfx",
    "certificate-password",
    X509KeyStorageFlags.Exportable
);
Imports System.Security.Cryptography.X509Certificates

' Load the certificate from a PKCS#12 file (.pfx or .p12)
' The Exportable flag allows the private key to be used for signing
Dim certificate As New X509Certificate2( _
    "company-signing-cert.pfx", _
    "certificate-password", _
    X509KeyStorageFlags.Exportable _
)
$vbLabelText   $csharpLabel

输出示例:

证书加载成功
  主题:CN=Test Signer, O=Test Organization, C=US
  签发人:CN=测试签发人,O=测试组织,C=美国
  有效期从2026-01-27 上午 7:50:04
  有效期至2027-01-27 上午 8:00:03
  缩略图:41355DE5ADD66CD64B2B99FF2CF87B9C87BD412F
  有私钥:真

在生产中,从 Azure Key Vault、AWS Secrets Manager 或 HashiCorp Vault 等安全配置系统中提取证书密码,而不是硬编码。 以适当的访问控制存储证书文件,切勿将其提交到版本控制中。


开发人员如何以编程方式在 PDF 文档中应用数字签名?

IronPDF 的基本签名工作流程包括从证书创建 PdfSignature 对象并将其应用于 PDF。 本节介绍签名过程以及添加元数据和配置签名行为的选项。

基本证书签名在 C# 中是什么样子的?

最简单的签名场景是加载现有的 PDF,通过证书创建签名并保存签名结果。 IronPDF 处理引擎盖下的所有加密操作:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/basic-signing.cs
using IronPdf;
using IronPdf.Signing;

// Load the PDF document that needs to be signed
PdfDocument pdf = PdfDocument.FromFile("contract.pdf");

// Create a signature object using the certificate file path and password
var signature = new PdfSignature("certificate.pfx", "password");

// Apply the cryptographic signature to the document
// This embeds an invisible digital signature in the PDF structure
pdf.Sign(signature);

// Save the signed document to a new file
pdf.SaveAs("contract-signed.pdf");
Imports IronPdf
Imports IronPdf.Signing

' Load the PDF document that needs to be signed
Dim pdf As PdfDocument = PdfDocument.FromFile("contract.pdf")

' Create a signature object using the certificate file path and password
Dim signature As New PdfSignature("certificate.pfx", "password")

' Apply the cryptographic signature to the document
' This embeds an invisible digital signature in the PDF structure
pdf.Sign(signature)

' Save the signed document to a new file
pdf.SaveAs("contract-signed.pdf")
$vbLabelText   $csharpLabel

输入

contract.pdf - 签订前的合同样本

contract.pdf - 签订前的合同样本

输出

这将创建一个嵌入了隐形数字签名的 PDF。 在 Adobe Acrobat 或其他可识别签名的 PDF 阅读器中打开时,文档会显示签名验证信息,显示签名是否有效以及签名后文档是否被修改过。

对于只需要签署文档而不需要将其加载到内存中进行其他修改的场景,IronPDF 有一种简化的单行方法:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/one-line-signing.cs
using IronPdf;
using IronPdf.Signing;

// One-line approach for signing PDFs
// Useful for batch processing where you don't need to manipulate the document
var signature = new PdfSignature("certificate.pfx", "password");
PdfDocument.FromFile("document.pdf").Sign(signature).SaveAs("document-signed.pdf");
Imports IronPdf
Imports IronPdf.Signing

' One-line approach for signing PDFs
' Useful for batch processing where you don't need to manipulate the document
Dim signature As New PdfSignature("certificate.pfx", "password")
PdfDocument.FromFile("document.pdf").Sign(signature).SaveAs("document-signed.pdf")
$vbLabelText   $csharpLabel

在签署大量文件而不做其他改动时,这对批量处理尤其方便。

如何为审计跟踪配置签名元数据?

数字签名可以携带元数据,提供签名事件的背景信息。 这些信息会显示在 PDF 阅读器的签名面板中,并添加到文档的审计跟踪中。 IronPdf 支持多个标准元数据字段:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/signature-metadata.cs
using IronPdf;
using IronPdf.Signing;
using System;

// Load the document to be signed
PdfDocument pdf = PdfDocument.FromFile("invoice.pdf");

// Create a signature with the company certificate
var signature = new PdfSignature("certificate.pfx", "password")
{
    // Add metadata to create an audit trail
    // This information appears in the signature panel of PDF readers
    SigningReason = "Invoice Approval",
    SigningLocation = "New York Office",
    SigningContact = "accounts@company.com",
    SignatureDate = DateTime.UtcNow
};

// Apply the signature with all metadata included
pdf.Sign(signature);
pdf.SaveAs("invoice-approved.pdf");
Imports IronPdf
Imports IronPdf.Signing
Imports System

' Load the document to be signed
Dim pdf As PdfDocument = PdfDocument.FromFile("invoice.pdf")

' Create a signature with the company certificate
Dim signature As New PdfSignature("certificate.pfx", "password") With {
    ' Add metadata to create an audit trail
    ' This information appears in the signature panel of PDF readers
    .SigningReason = "Invoice Approval",
    .SigningLocation = "New York Office",
    .SigningContact = "accounts@company.com",
    .SignatureDate = DateTime.UtcNow
}

' Apply the signature with all metadata included
pdf.Sign(signature)
pdf.SaveAs("invoice-approved.pdf")
$vbLabelText   $csharpLabel

输入

invoice.pdf - 签署前的发票

invoice.pdf - 签署前的发票

输出

元数据字段在文档工作流程中起着不同的作用:

元数据字段 翻译目的 示例价值
签署理由 解释签署文件的原因 "合同审批"、"审计认证"
签署地点 签署地点记录 "纽约办公室"、"远程家庭办公室
签署联系 提供咨询联系信息 "legal@company.com"、"+1 555 0123"
签名日期 为签署事件打上时间戳 `DateTime.UtcNow`

在企业环境中,这些领域通常与运营数据相关联。 发票审批系统可能会将签署原因设置为采购订单号,而合同管理系统则可能包括合同 ID 和审批阶段。

时间戳服务器在随时间变化的签名有效性中扮演什么角色?

数字签名包含一个时间戳,显示文件的签名时间,但该时间戳来自签名计算机的本地时钟。 对于多年后可能需要验证的签名,或者在法律上需要证明准确签名时间时,来自外部时间戳权威机构(TSA)的可信时间戳可以提供更有力的证据。

时间戳服务器可提供加密证明,证明文档在特定时刻以当前形式存在。 即使签名证书后来过期或被撤销,时间戳也会显示签名在应用时是有效的。 IronPDF 支持 RFC 3161 时间戳服务器:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/timestamp-server.cs
using IronPdf;
using IronPdf.Signing;
using System;

// Load the document to sign
PdfDocument pdf = PdfDocument.FromFile("agreement.pdf");
var signature = new PdfSignature("certificate.pfx", "password")
{
    SigningReason = "Agreement Execution",
    // Configure a trusted timestamp server (RFC 3161 compliant)
    // This provides cryptographic proof of when the document was signed
    TimestampHashAlgorithm = TimestampHashAlgorithms.SHA256,
    TimeStampUrl = "http://timestamp.digicert.com"
};

// Apply the signature with the trusted timestamp
pdf.Sign(signature);
pdf.SaveAs("agreement-timestamped.pdf");
Imports IronPdf
Imports IronPdf.Signing
Imports System

' Load the document to sign
Dim pdf As PdfDocument = PdfDocument.FromFile("agreement.pdf")
Dim signature As New PdfSignature("certificate.pfx", "password") With {
    .SigningReason = "Agreement Execution",
    ' Configure a trusted timestamp server (RFC 3161 compliant)
    ' This provides cryptographic proof of when the document was signed
    .TimestampHashAlgorithm = TimestampHashAlgorithms.SHA256,
    .TimeStampUrl = "http://timestamp.digicert.com"
}

' Apply the signature with the trusted timestamp
pdf.Sign(signature)
pdf.SaveAs("agreement-timestamped.pdf")
$vbLabelText   $csharpLabel

输入

agreement.pdf - 签署前的服务协议

agreement.pdf - 签署前的服务协议

输出

有几种公共时间戳服务器可供普遍使用,包括由主要证书颁发机构运营的服务器。 规模较大的组织也可能运行自己的内部时间戳服务器,并遵循公司的安全政策。

哈希算法的选择对扩展有效性很重要。 SHA 256 是当前的标准,不过 IronPDF 也支持 SHA 512 以满足更严格的安全要求。 应避免使用 SHA 1 等旧算法,因为它们不再被视为加密安全算法。

什么情况下签名应在文档上不可见,什么情况下签名应在文档上可见?

数字签名有两种应用模式:一种是只存在于 PDF 密码结构中的不可见签名,另一种是在指定页面上显示图形的可见签名。 选择取决于文件的目的和收件人的期望。

隐形签名适用于自动文档处理(不需要人工审核)、现有文档布局不应改变的情况,以及多签名工作流程(可见签名会使文档变得杂乱)。

如果收件人希望看到签名的直观证据,工作流程要求将签名放在特定位置,或者文件将被打印,签名应显示在纸上,则首选可见签名。

下一节将详细介绍可视化签名的实现。


如何在数字签名 PDF 中添加可视签名外观?

许多业务流程都是围绕可见签名块发展起来的,收件人通常希望看到文档的签名位置和时间。 IronPDF 允许您应用加密保护,同时还能在页面上显示可见签名,让您两全其美。

如何加载和定位签名图像?

视觉签名通常是指在 PDF 页面特定位置放置的图像(如扫描的手写签名、公司印章或样式文本块)。 IronPdf 的 LoadSignatureImageFromFile 方法负责定位和渲染:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/visual-signature.cs
using IronPdf;
using IronPdf.Signing;
using IronSoftware.Drawing;

// Load the document to sign
PdfDocument pdf = PdfDocument.FromFile("contract.pdf");
var signature = new PdfSignature("certificate.pfx", "password")
{
    SigningReason = "Contract Approval",
    SigningLocation = "Head Office"
};

// Define the position and size for the visible signature image
// Rectangle parameters: x position, y position, width, height (in points)
// Points are measured from the bottom-left corner of the page
var signatureArea = new Rectangle(150, 100, 200, 50);

// Load and attach the visual signature image
// The image will appear at the specified location on the document
signature.LoadSignatureImageFromFile(
    "signature-image.png",   // Path to the signature image file
    0,                       // Page index (0 = first page)
    signatureArea            // Position and dimensions
);

// Apply both the cryptographic signature and visual representation
pdf.Sign(signature);
pdf.SaveAs("contract-visually-signed.pdf");
Imports IronPdf
Imports IronPdf.Signing
Imports IronSoftware.Drawing

' Load the document to sign
Dim pdf As PdfDocument = PdfDocument.FromFile("contract.pdf")
Dim signature As New PdfSignature("certificate.pfx", "password") With {
    .SigningReason = "Contract Approval",
    .SigningLocation = "Head Office"
}

' Define the position and size for the visible signature image
' Rectangle parameters: x position, y position, width, height (in points)
' Points are measured from the bottom-left corner of the page
Dim signatureArea As New Rectangle(150, 100, 200, 50)

' Load and attach the visual signature image
' The image will appear at the specified location on the document
signature.LoadSignatureImageFromFile(
    "signature-image.png",   ' Path to the signature image file
    0,                       ' Page index (0 = first page)
    signatureArea            ' Position and dimensions
)

' Apply both the cryptographic signature and visual representation
pdf.Sign(signature)
pdf.SaveAs("contract-visually-signed.pdf")
$vbLabelText   $csharpLabel

输出

坐标系使用从页面左下角开始测量的点(1/72 英寸)。 对于标准的 US Letter 页面(612 x 792 点),将签名放在右下角附近意味着要考虑签名尺寸和适当的页边距。

从不同来源加载签名图像有其他方法:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/load-signature-image.cs
using IronPdf.Signing;
using IronSoftware.Drawing;
using System.IO;

// Create signature object
var signature = new PdfSignature("certificate.pfx", "password");
var signatureArea = new Rectangle(400, 50, 150, 75);

// Method 1: Load signature image directly from a file path
signature.LoadSignatureImageFromFile("signature.png", 0, signatureArea);

// Method 2: Load from a stream (useful for database-stored images)
using (FileStream imageStream = File.OpenRead("signature.png"))
{
    signature.LoadSignatureImageFromStream(imageStream, 0, signatureArea);
}

// Method 3: Load from AnyBitmap (IronSoftware's cross-platform image type)
AnyBitmap signatureBitmap = AnyBitmap.FromFile("signature.png");
using (var stream = signatureBitmap.ToStream())
{
    signature.LoadSignatureImageFromStream(stream, 0, signatureArea);
}
Imports IronPdf.Signing
Imports IronSoftware.Drawing
Imports System.IO

' Create signature object
Dim signature As New PdfSignature("certificate.pfx", "password")
Dim signatureArea As New Rectangle(400, 50, 150, 75)

' Method 1: Load signature image directly from a file path
signature.LoadSignatureImageFromFile("signature.png", 0, signatureArea)

' Method 2: Load from a stream (useful for database-stored images)
Using imageStream As FileStream = File.OpenRead("signature.png")
    signature.LoadSignatureImageFromStream(imageStream, 0, signatureArea)
End Using

' Method 3: Load from AnyBitmap (IronSoftware's cross-platform image type)
Dim signatureBitmap As AnyBitmap = AnyBitmap.FromFile("signature.png")
Using stream = signatureBitmap.ToStream()
    signature.LoadSignatureImageFromStream(stream, 0, signatureArea)
End Using
$vbLabelText   $csharpLabel

支持的图像格式包括 PNG、JPEG、GIF、BMP、TIFF 和 WebP。具有透明度的 PNG 文件非常适合用于签名图像,因为透明背景可以让底层文档内容显示出来。

签名定位如何跨多个页面工作?

在签署多页文档时,无论页数多少,数字签名都将保护整个文档。 PDF 中的所有页面都有一个加密签名:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/multi-page-signing.cs
using IronPdf;
using IronPdf.Signing;

// Load a multi-page document
PdfDocument pdf = PdfDocument.FromFile("multi-page-contract.pdf");

// Create signature - digital signatures protect the entire document
// regardless of page count
var signature = new PdfSignature("certificate.pfx", "password");

// Sign and save the document
// The signature applies to all pages in the document
pdf.Sign(signature);
pdf.SaveAs("contract-signed-last-page.pdf");
Imports IronPdf
Imports IronPdf.Signing

' Load a multi-page document
Dim pdf As PdfDocument = PdfDocument.FromFile("multi-page-contract.pdf")

' Create signature - digital signatures protect the entire document
' regardless of page count
Dim signature As New PdfSignature("certificate.pfx", "password")

' Sign and save the document
' The signature applies to all pages in the document
pdf.Sign(signature)
pdf.SaveAs("contract-signed-last-page.pdf")
$vbLabelText   $csharpLabel

输入

多页合同.pdf(最后一页)- 签署前的签名页

多页合同.pdf(最后一页)- 签署前的签名页

输出

对于多页上的签名(如法律协议每页上的首字母缩写),开发人员可以在加密签名之外单独应用图像印章:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/initials-stamp.cs
using IronPdf;
using IronPdf.Editing;
using IronPdf.Signing;
using IronSoftware.Drawing;

// Load the document
PdfDocument pdf = PdfDocument.FromFile("agreement.pdf");

// Create an image stamp for initials that will appear on every page
var initialsStamp = new ImageStamper("initials.png")
{
    HorizontalAlignment = HorizontalAlignment.Right,
    VerticalAlignment = VerticalAlignment.Bottom,
    HorizontalOffset = new Length(50, MeasurementUnit.Points),
    VerticalOffset = new Length(50, MeasurementUnit.Points)
};

// Apply initials stamp to all pages
pdf.ApplyStamp(initialsStamp);

// Now apply the cryptographic signature with a full signature image on the last page
var signature = new PdfSignature("certificate.pfx", "password");
var signatureArea = new Rectangle(100, 100, 200, 100);
signature.SignatureImage = new PdfSignatureImage(
    "full-signature.png",
    pdf.PageCount - 1,    // Last page only
    signatureArea
);

// Sign the entire document cryptographically
pdf.Sign(signature);
pdf.SaveAs("agreement-initialed-and-signed.pdf");
Imports IronPdf
Imports IronPdf.Editing
Imports IronPdf.Signing
Imports IronSoftware.Drawing

' Load the document
Dim pdf As PdfDocument = PdfDocument.FromFile("agreement.pdf")

' Create an image stamp for initials that will appear on every page
Dim initialsStamp As New ImageStamper("initials.png") With {
    .HorizontalAlignment = HorizontalAlignment.Right,
    .VerticalAlignment = VerticalAlignment.Bottom,
    .HorizontalOffset = New Length(50, MeasurementUnit.Points),
    .VerticalOffset = New Length(50, MeasurementUnit.Points)
}

' Apply initials stamp to all pages
pdf.ApplyStamp(initialsStamp)

' Now apply the cryptographic signature with a full signature image on the last page
Dim signature As New PdfSignature("certificate.pfx", "password")
Dim signatureArea As New Rectangle(100, 100, 200, 100)
signature.SignatureImage = New PdfSignatureImage(
    "full-signature.png",
    pdf.PageCount - 1,    ' Last page only
    signatureArea
)

' Sign the entire document cryptographically
pdf.Sign(signature)
pdf.SaveAs("agreement-initialed-and-signed.pdf")
$vbLabelText   $csharpLabel

这种方法将视觉元素(可出现在多个页面上)与加密签名(保护整个文档)分离开来。


多方签名工作流如何在企业应用程序中发挥作用?

复杂的业务流程往往需要不同人员按照特定顺序进行多次签名。 采购订单可能需要部门经理批准,然后财务部门审核,最后行政部门签字。 IronPDF 通过增量保存和签名权限支持这些工作流程。

什么是顺序签名,增量保存如何实现顺序签名?

PDF 文档可以在内部存储多个修订版本,类似于版本控制。 每次有人签名时,该签名都适用于文档当时的状态。 后来的签名者会在新的修订版上添加他们的签名,这样就形成了一个审批链,每个签名都可以独立验证。

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/sequential-signing-first.cs
using IronPdf;
using IronPdf.Signing;

// Load the purchase order document
PdfDocument pdf = PdfDocument.FromFile("purchase-order.pdf");

// First signer: Department Manager approves the purchase order
var managerSignature = new PdfSignature("certificate.pfx", "password")
{
    SigningReason = "Manager Approval",
    SigningLocation = "Department A"
};

// Sign the document and save
// This preserves the original state while adding the signature
pdf.Sign(managerSignature);
pdf.SaveAs("po-manager-approved.pdf");
Imports IronPdf
Imports IronPdf.Signing

' Load the purchase order document
Dim pdf As PdfDocument = PdfDocument.FromFile("purchase-order.pdf")

' First signer: Department Manager approves the purchase order
Dim managerSignature As New PdfSignature("certificate.pfx", "password") With {
    .SigningReason = "Manager Approval",
    .SigningLocation = "Department A"
}

' Sign the document and save
' This preserves the original state while adding the signature
pdf.Sign(managerSignature)
pdf.SaveAs("po-manager-approved.pdf")
$vbLabelText   $csharpLabel

输入

purchase-order.pdf - 等待审批的采购订单

purchase-order.pdf - 等待审批的采购订单

输出

当文档转到下一个审批人时,他们会加载文档并添加自己的签名:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/sequential-signing-second.cs
using IronPdf;
using IronPdf.Signing;

// Load the document that already has the manager's signature
PdfDocument pdf = PdfDocument.FromFile("po-manager-approved.pdf");

// Second signer: Finance department verifies budget availability
var financeSignature = new PdfSignature("certificate.pfx", "password")
{
    SigningReason = "Finance Approval",
    SigningLocation = "Finance Department"
};

// Add the second signature
// Both signatures remain independently verifiable
pdf.Sign(financeSignature);
pdf.SaveAs("po-finance-approved.pdf");
Imports IronPdf
Imports IronPdf.Signing

' Load the document that already has the manager's signature
Dim pdf As PdfDocument = PdfDocument.FromFile("po-manager-approved.pdf")

' Second signer: Finance department verifies budget availability
Dim financeSignature As New PdfSignature("certificate.pfx", "password") With {
    .SigningReason = "Finance Approval",
    .SigningLocation = "Finance Department"
}

' Add the second signature
' Both signatures remain independently verifiable
pdf.Sign(financeSignature)
pdf.SaveAs("po-finance-approved.pdf")
$vbLabelText   $csharpLabel

输出

每个修订版都有自己的签名,PDF 阅读器可以显示签名者的完整历史记录。

在添加新签名之前,如何验证现有签名?

在向文档添加新签名之前,您的代码应验证现有签名是否仍然有效。 在正确的工作流程之外修改的文档可能会有无效签名,这可能表明存在篡改或违反流程的情况。

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/verify-signatures.cs
using IronPdf;
using System;

// Load a signed document
PdfDocument pdf = PdfDocument.FromFile("contract-signed.pdf");

// Verify all existing signatures in the document
// Returns true only if ALL signatures are valid and untampered
bool isValid = pdf.VerifyPdfSignatures();

Console.WriteLine($"Signatures Valid: {isValid}");

// Get signature details
var signatures = pdf.GetVerifiedSignatures();
Console.WriteLine($"Number of Signatures: {signatures.Count}");
Imports IronPdf
Imports System

' Load a signed document
Dim pdf As PdfDocument = PdfDocument.FromFile("contract-signed.pdf")

' Verify all existing signatures in the document
' Returns true only if ALL signatures are valid and untampered
Dim isValid As Boolean = pdf.VerifyPdfSignatures()

Console.WriteLine($"Signatures Valid: {isValid}")

' Get signature details
Dim signatures = pdf.GetVerifiedSignatures()
Console.WriteLine($"Number of Signatures: {signatures.Count}")
$vbLabelText   $csharpLabel

要进行更详细的检查,您可以检索每个已验证签名的相关信息:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/get-verified-signatures.cs
using IronPdf;
using System;

// Load a document with multiple signatures
PdfDocument pdf = PdfDocument.FromFile("multi-signed-document.pdf");

// Retrieve detailed information about each verified signature
var verifiedSignatures = pdf.GetVerifiedSignatures();

// Iterate through all signatures to build an audit trail
foreach (var sig in verifiedSignatures)
{
    Console.WriteLine($"Signer: {sig.SignerName}");
    Console.WriteLine($"Reason: {sig.SigningReason}");
    Console.WriteLine($"Location: {sig.SigningLocation}");
    Console.WriteLine($"Date: {sig.SigningDate}");
    Console.WriteLine($"Contact: {sig.SigningContact}");
    Console.WriteLine("---");
}
Imports IronPdf
Imports System

' Load a document with multiple signatures
Dim pdf As PdfDocument = PdfDocument.FromFile("multi-signed-document.pdf")

' Retrieve detailed information about each verified signature
Dim verifiedSignatures = pdf.GetVerifiedSignatures()

' Iterate through all signatures to build an audit trail
For Each sig In verifiedSignatures
    Console.WriteLine($"Signer: {sig.SignerName}")
    Console.WriteLine($"Reason: {sig.SigningReason}")
    Console.WriteLine($"Location: {sig.SigningLocation}")
    Console.WriteLine($"Date: {sig.SigningDate}")
    Console.WriteLine($"Contact: {sig.SigningContact}")
    Console.WriteLine("---")
Next
$vbLabelText   $csharpLabel

有了这些信息,您就可以建立审计跟踪、验证审批链,并确保文件在进入下一阶段之前拥有所有必要的签名。

IronPDF 如何检测篡改文档?

如果文档中的任何签名无效,VerifyPdfSignatures() 方法将返回 false。 这种情况通常发生在文档签名后内容被修改、签名数据本身已损坏、证书已被撤销或证书在使用时尚未生效的情况下。

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/detect-tampering.cs
using IronPdf;
using System;

// Load a signed document and verify
PdfDocument pdf = PdfDocument.FromFile("contract-signed.pdf");

// Check if all signatures are still valid
bool isValid = pdf.VerifyPdfSignatures();

if (isValid)
{
    Console.WriteLine("Document has not been tampered with");
    Console.WriteLine("All signatures are valid");
}
else
{
    Console.WriteLine("WARNING: Document may have been tampered with!");
    Console.WriteLine("One or more signatures are invalid");
}
Imports IronPdf
Imports System

' Load a signed document and verify
Dim pdf As PdfDocument = PdfDocument.FromFile("contract-signed.pdf")

' Check if all signatures are still valid
Dim isValid As Boolean = pdf.VerifyPdfSignatures()

If isValid Then
    Console.WriteLine("Document has not been tampered with")
    Console.WriteLine("All signatures are valid")
Else
    Console.WriteLine("WARNING: Document may have been tampered with!")
    Console.WriteLine("One or more signatures are invalid")
End If
$vbLabelText   $csharpLabel

对于需要移除签名的应用程序(也许是为了创建一份未签名的副本用于再分发),IronPDF 提供了 RemoveSignatures() 方法:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/remove-signatures.cs
using IronPdf;

// Load a signed document
PdfDocument pdf = PdfDocument.FromFile("signed-template.pdf");

// Remove all digital signatures from the document
// This strips signature data but does not restore previous document state
pdf.RemoveSignatures();

// Save as an unsigned version
pdf.SaveAs("unsigned-template.pdf");
Imports IronPdf

' Load a signed document
Dim pdf As PdfDocument = PdfDocument.FromFile("signed-template.pdf")

' Remove all digital signatures from the document
' This strips signature data but does not restore previous document state
pdf.RemoveSignatures()

' Save as an unsigned version
pdf.SaveAs("unsigned-template.pdf")
$vbLabelText   $csharpLabel

请注意,删除签名并不能恢复之前的文档状态。 该方法只需从当前文档版本中删除签名数据即可。


哪些技术能力支持 PDF 签名符合法规要求?

不同司法管辖区和行业的数字签名法规各不相同,但它们在证书验证、时间戳和签名元数据方面有着共同的技术需求。 本节将重点介绍合规性框架通常要求的技术能力,而不是试图解释具体的法律规定(您应与合格的法律顾问进行讨论)。

数字签名的主要监管框架是什么?

下表总结了常见的监管框架及其一般技术要求:

框架 管辖权 关键技术要求
ESIGN 法案 美国 签署意向、电子记录同意书、记录保留
UETA 美国 与 ESIGN 类似,适用于国内交易
eIDAS 欧盟 三个签名级别(简单、高级、合格);合格需要 QSCD
21 CFR 第 11 部分 美国 FDA 电子签名必须与电子记录、审计跟踪相关联

这些框架通常承认数字签名在正确实施后在法律上等同于手写签名。 数字签名的证据价值往往取决于能否证明签名在应用时是有效的,这也是可信时间戳对于保存数年或数十年的文件至关重要的地方。

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/compliance-signing.cs
using IronPdf;
using IronPdf.Signing;
using System;

// Load the compliance document
PdfDocument pdf = PdfDocument.FromFile("compliance-document.pdf");
var signature = new PdfSignature("certificate.pfx", "password")
{
    // Add comprehensive metadata for audit trail requirements
    SigningReason = "21 CFR Part 11 Compliance Certification",
    SigningLocation = "Quality Assurance Department",
    SigningContact = "compliance@company.com",
    SignatureDate = DateTime.UtcNow,
    // Configure a trusted timestamp for regulatory compliance
    // The timestamp proves when the signature was applied
    TimestampHashAlgorithm = TimestampHashAlgorithms.SHA256,
    TimeStampUrl = "http://timestamp.digicert.com"
};

// Apply the signature with timestamp and full metadata
pdf.Sign(signature);
pdf.SaveAs("compliance-document-certified.pdf");
Imports IronPdf
Imports IronPdf.Signing
Imports System

' Load the compliance document
Dim pdf As PdfDocument = PdfDocument.FromFile("compliance-document.pdf")
Dim signature As New PdfSignature("certificate.pfx", "password") With {
    ' Add comprehensive metadata for audit trail requirements
    .SigningReason = "21 CFR Part 11 Compliance Certification",
    .SigningLocation = "Quality Assurance Department",
    .SigningContact = "compliance@company.com",
    .SignatureDate = DateTime.UtcNow,
    ' Configure a trusted timestamp for regulatory compliance
    ' The timestamp proves when the signature was applied
    .TimestampHashAlgorithm = TimestampHashAlgorithms.SHA256,
    .TimeStampUrl = "http://timestamp.digicert.com"
}

' Apply the signature with timestamp and full metadata
pdf.Sign(signature)
pdf.SaveAs("compliance-document-certified.pdf")
$vbLabelText   $csharpLabel

输入

compliance-document.pdf - 等待认证的合规文件

compliance-document.pdf - 等待认证的合规文件

输出

哪些证书要求适用于受监管行业?

不同的监管环境可能会规定用于签名的证书的标准。 这些标准可能包括由经认可的机构签发、最小密钥长度(通常为 2048 位 RSA 或同等长度)、特定的扩展密钥使用属性,或使用 HSM 或智能卡解决方案进行基于硬件的密钥存储。

IronPdf 可与任何符合标准规范的 X.509 证书一起使用,允许您使用自己偏好的证书颁发机构颁发的证书。 对于需要硬件保护密钥的环境,IronPdf 通过其 HsmSigner 功能支持基于 PKCS#11 的 HSM 集成。

受监管行业的开发人员应与其法律和合规部门合作,确定所需的内容,然后建立与之相匹配的签名基础架构。

签名权限控制如何支持文档生命周期管理?

文件签署后,有时需要出于特定目的保持可编辑性,如允许其他签署人添加签名或允许填写表格字段。 IronPdf 的 SignaturePermissions 枚举可控制签署后允许进行哪些更改:

:path=/static-assets/pdf/content-code-examples/tutorials/pdf-digital-signatures-csharp-guide/signature-permissions.cs
using IronPdf;
using IronPdf.Signing;

// Load a form document that needs signing
PdfDocument pdf = PdfDocument.FromFile("approval-form.pdf");

// Sign with specific permissions for document lifecycle management
// AdditionalSignaturesAndFormFillingAllowed permits form completion and additional signatures after signing
pdf.SignWithFile(
    "approver-cert.pfx",
    "password",
    null,
    SignaturePermissions.AdditionalSignaturesAndFormFillingAllowed
);

// Save the signed document with form-filling permissions enabled
pdf.SaveAs("approval-form-signed.pdf");
Imports IronPdf
Imports IronPdf.Signing

' Load a form document that needs signing
Dim pdf As PdfDocument = PdfDocument.FromFile("approval-form.pdf")

' Sign with specific permissions for document lifecycle management
' AdditionalSignaturesAndFormFillingAllowed permits form completion and additional signatures after signing
pdf.SignWithFile(
    "approver-cert.pfx",
    "password",
    Nothing,
    SignaturePermissions.AdditionalSignaturesAndFormFillingAllowed
)

' Save the signed document with form-filling permissions enabled
pdf.SaveAs("approval-form-signed.pdf")
$vbLabelText   $csharpLabel

可用权限级别为

许可级别 签署后允许的更改
`不允许更改` 文档完全锁定
`允许填写表格` 只能填写表格字段;不能更改内容
`允许附加签名和填写表格` 允许填写表格和附加签名
`FormFillingAndAnnotationsAllowed` 允许填写表格并加上注释

适当的权限级别取决于文档的作用。 已完成的协议可能会使用 NoChangesAllowed ,而仍在进行中的审批表可能会使用 AdditionalSignaturesAndFormFillingAllowed 以允许其他审批人填写表格并进行额外签名。


何时构建自定义签名比使用外部服务更有意义?

任何实施文档签名的人都会面临一个基本的架构决策:在自己的应用程序中构建签名功能,还是使用托管签名服务。 这两种方法各有千秋,正确的选择取决于数量、定制需求、合规性考虑以及总体拥有成本。

哪些因素有利于构建内部签名功能?

以下是直接在应用程序中构建签名功能的一些应用场景:

文件量大使得规模化的每笔交易定价昂贵。 每月处理数千份文档的企业通常会发现,与按签名收取 API 费用相比,IronPDF 这样的永久许可证库具有更好的经济效益。 与持续的交易成本相比,一次性许可投资很快就能收回成本。

独特的流程要求当外部签名服务具有自己的范例时就会出现。 如果团队有不寻常的审批流程、专门的文档处理或不适合标准产品的集成需求,那么他们通常会发现构建自己的解决方案比试图适应服务的局限性要容易得多。

数据主权和安全政策由于法规、安全政策或合同义务,一些公司无法将文档发送到外部服务。 签署过程必须在公司内部进行,以确保文件始终在公司范围内。

离线或空中环境不能依赖需要网络连接的托管解决方案。 必须在断网环境中工作的应用程序(现场服务应用程序、分类系统或互联网不稳定的地方)需要本地实施的签名功能。

成本可预测性非常重要,因为基于订阅的定价会产生累积的持续费用。 永久库许可证提供了稳定的成本,财务部门可以据此制定计划,而不必担心数量波动或价格上涨。

哪些场景青睐托管签名解决方案?

托管解决方案在不同情况下效果良好:

不同签署方的低翻译量当文件需要公司外部人员的签名,而这些人又没有自己的证书时就会出现这种情况。 处理身份验证和证书签发的服务可减少摩擦。 在内部建立这种基础架构很少能为偶尔使用带来回报。

快速部署在您需要在没有开发资源从头开始构建的情况下快速启动和运行签名时非常重要。 这些平台配有现成的用户界面和电子邮件通知,可提供交钥匙功能。

合规性委托在供应商专注于特定监管框架并能提供独立获取成本高昂的认证或证明时变得非常有价值。

通常要决定的是,签约是一种值得投资的核心能力,还是一种最好留给专家的商品功能。 将处理文件作为业务核心部分的企业(律师事务所、金融机构、医疗保健提供商、政府机构)通常会从拥有自己的签名基础设施中获得更好的回报。 文档签署是次要工作的开发人员可能更倾向于选择简单的外包服务。

开发团队如何评估其签名基础设施需求?

在采用这两种方法之前,请考虑以下因素:

当前和预计数量驱动您的成本分析。 现在有多少文件需要签名,随着时间的推移会有什么变化?

集成考虑因素会影响您的架构。 签名如何融入现有应用程序和工作流程? 库提供了最大的灵活性,而外部平台可能需要适应其 API 和用户界面。

签署方类型会影响复杂性。 文件仅由内部用户使用管理证书签署,还是也需要外部签署者?

合规环境决定了技术要求。 适用哪些法规,它们如何影响您的实施选择? 有些任务更容易通过服务来完成; 其他需要内部控制。

技术资源决定可行性。 团队是否有足够的带宽来实施和维护签名功能,还是说这样会分散核心开发重点的精力?


下一步

在 .NET 应用程序中构建数字签名意味着既要了解加密基础知识,又要了解推动业务文档处理的实际需求。 IronPDF基于证书的签名可视签名渲染、多方工作流支持和签名验证提供了技术基础,同时将有关何时以及如何使用这些功能的架构决策留给了解其特定需求的开发人员。

无论您是要自动执行合同、实施审批链,还是要满足合规性要求,本指南所涵盖的功能都为可靠的签名实施提供了基石。 对于需要硬件支持密钥存储的企业环境,HSM 签名指南将这些模式扩展到 PKCS#11 设备。 当签名是更广泛的文档安全策略的一部分时,请将其与密码保护和权限以及PDF加密相结合,以实现分层防御。

准备好开始构建了吗? 下载 IronPDF 并免费试用。 在做出任何购买决定之前,您可以使用实际文档对基于证书的签名、签名验证和多方工作流进行评估。 如果您对签名架构或合规性集成有任何疑问,请联系我们的工程支持团队

常见问题解答

PDF 中的数字签名是什么?

数字签名是一种加密机制,用于验证 PDF 文档的真实性和完整性。它确保文档未被篡改,并确认签名者的身份。

如何使用 IronPDF 在 C# 中实现数字签名?

IronPDF 提供了使用 C# 在 PDF 中实现数字签名的直接 API。您可以通过使用证书签名、添加可视化签名和管理多方工作流,以编程方式签署文档。

IronPDF 支持哪些类型的数字签名?

IronPdf 支持各种类型的数字签名,包括基于证书的签名、可视签名以及需要时间戳服务器进行额外验证的签名。

能否使用 IronPDF 验证 PDF 中的数字签名?

是的,IronPDF 包含用于验证 PDF 文档中数字签名的功能,可确保文档是真实的,自签名以来未被篡改。

时间戳服务器在数字签名中的作用是什么?

时间戳服务器提供了一个可信的时间源,用于确认数字签名何时应用于文档。这通过验证签名的确切时间增加了一层额外的安全性。

可视签名与数字证书有何不同?

可视签名在文档上显示签名的图形表示,而数字证书提供真实性和完整性的加密证明,但不一定显示可视标记。

IronPDF 能否处理多方签名工作流?

是的,IronPDF 能够管理多方签名工作流,允许多方以协调、安全的方式签署文档。

在 PDF 文档中使用数字签名有什么好处?

数字签名可确保文档的完整性和真实性,从而提高安全性。数字签名还能实现电子签名,比传统方法更快、更高效,从而简化工作流程。

是否可以在没有用户交互的情况下以编程方式签署 PDF?

是的,有了 IronPDF,您可以用 C# 编程签署 PDF,无需用户交互,非常适合自动化工作流和批量处理。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

准备开始了吗?
Nuget 下载 17,386,124 | 版本: 2026.2 刚刚发布