作法:使用數位簽章簽署 XML 文件

您可以使用 System.Security.Cryptography.Xml 命名空間中的類別,以數位簽章簽署 XML 文件或 XML 文件的一部分。 XML 數位簽章 (XMLDSIG) 可讓您驗證在簽署資料後,資料未經過變更。 如需 XMLDSIG 標準的詳細資訊,請參閱全球資訊網協會 (W3C) 的建議 XML 簽章語法和處理

注意

本文中的程式碼適用於 Windows。

這個程序中的程式碼範例會示範如何數位簽署整份 XML 文件,並將簽章附加到 <Signature> 元素的文件中。 範例會建立 RSA 簽章金鑰、將金鑰加入安全的金鑰容器,然後使用金鑰來數位簽署 XML 文件。 金鑰便可以擷取來驗證 XML 數位簽章,或可以用來簽署另一份 XML 文件。

如需如何驗證使用此程序建立之 XML 數位簽章的相關資訊,請參閱 如何:驗證 XML 文件的數位簽章

數位簽署 XML 文件

  1. 建立 CspParameters 物件,並指定金鑰容器的名稱。

    CspParameters cspParams = new()
    {
        KeyContainerName = "XML_DSIG_RSA_KEY"
    };
    
    Dim cspParams As New CspParameters With {
        .KeyContainerName = "XML_DSIG_RSA_KEY"
    }
    
  2. 使用 RSACryptoServiceProvider 類別產生非對稱金鑰。 當您將 CspParameters 物件傳遞到 RSACryptoServiceProvider 類別的建構函式時,金鑰會自動儲存到金鑰容器。 此金鑰會用來簽署 XML 文件。

    RSACryptoServiceProvider rsaKey = new(cspParams);
    
    Dim rsaKey As New RSACryptoServiceProvider(cspParams)
    
  3. 藉由從磁碟載入 XML 檔案,建立 XmlDocument 物件。 XmlDocument 物件會包含要加密的 XML 項目。

    XmlDocument xmlDoc = new()
    {
        // Load an XML file into the XmlDocument object.
        PreserveWhitespace = true
    };
    xmlDoc.Load("test.xml");
    
    ' Load an XML file into the XmlDocument object.
    Dim xmlDoc As New XmlDocument With {
        .PreserveWhitespace = True
    }
    xmlDoc.Load("test.xml")
    
  4. 建立新的 SignedXml 物件,並傳遞 XmlDocument 物件給它。

    SignedXml signedXml = new(xmlDoc)
    {
    
    Dim signedXml As New SignedXml(xmlDoc)
    
  5. 將簽署的 RSA 金鑰加入 SignedXml 物件。

        SigningKey = rsaKey
    };
    
    signedXml.SigningKey = rsaKey
    
  6. 建立描述要簽署項目的 Reference 物件。 若要簽署整份文件,請將 Uri 屬性設為 ""

    // Create a reference to be signed.
    Reference reference = new()
    {
        Uri = ""
    };
    
    ' Create a reference to be signed.
    Dim reference As New Reference()
    reference.Uri = ""
    
  7. XmlDsigEnvelopedSignatureTransform 物件加入 Reference 物件。 轉換可讓驗證器工具以簽署者使用的相同方式代表 XML 資料。 XML 資料可以用不同的方式代表,因此這個步驟對於驗證很重要。

    XmlDsigEnvelopedSignatureTransform env = new();
    reference.AddTransform(env);
    
    Dim env As New XmlDsigEnvelopedSignatureTransform()
    reference.AddTransform(env)
    
  8. Reference 物件加入 SignedXml 物件。

    signedXml.AddReference(reference);
    
    signedXml.AddReference(reference)
    
  9. 呼叫 ComputeSignature 方法來計算簽章。

    signedXml.ComputeSignature();
    
    signedXml.ComputeSignature()
    
  10. 擷取簽章的 XML 表示 (<Signature> 元素),並將它儲存在新的 XmlElement 物件內。

    XmlElement xmlDigitalSignature = signedXml.GetXml();
    
    Dim xmlDigitalSignature As XmlElement = signedXml.GetXml()
    
  11. 將項目附加至 XmlDocument 物件。

    xmlDoc.DocumentElement?.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
    
    xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, True))
    
  12. 儲存文件。

    xmlDoc.Save("test.xml");
    
    xmlDoc.Save("test.xml")
    

範例

這個範例假設名為 test.xml 的檔案已存在於和編譯程式相同的目錄中。 您可以將下列 XML 放入稱為 test.xml 的檔案,並使用它搭配此範例。

<root>  
    <creditcard>  
        <number>19834209</number>  
        <expiry>02/02/2002</expiry>  
    </creditcard>  
</root>  
using System;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Xml;

[SupportedOSPlatform("Windows")]
public class SignXML
{
    public static void Main(String[] args)
    {
        try
        {
            // Create a new CspParameters object to specify
            // a key container.
            CspParameters cspParams = new()
            {
                KeyContainerName = "XML_DSIG_RSA_KEY"
            };

            // Create a new RSA signing key and save it in the container.
            RSACryptoServiceProvider rsaKey = new(cspParams);

            // Create a new XML document.
            XmlDocument xmlDoc = new()
            {
                // Load an XML file into the XmlDocument object.
                PreserveWhitespace = true
            };
            xmlDoc.Load("test.xml");

            // Sign the XML document.
            SignXml(xmlDoc, rsaKey);

            Console.WriteLine("XML file signed.");

            // Save the document.
            xmlDoc.Save("test.xml");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    // Sign an XML file.
    // This document cannot be verified unless the verifying
    // code has the key with which it was signed.
    public static void SignXml(XmlDocument xmlDoc, RSA rsaKey)
    {
        // Check arguments.
        if (xmlDoc == null)
            throw new ArgumentException(null, nameof(xmlDoc));
        if (rsaKey == null)
            throw new ArgumentException(null, nameof(rsaKey));

        // Create a SignedXml object.
        SignedXml signedXml = new(xmlDoc)
        {

            // Add the key to the SignedXml document.
            SigningKey = rsaKey
        };

        // Create a reference to be signed.
        Reference reference = new()
        {
            Uri = ""
        };

        // Add an enveloped transformation to the reference.
        XmlDsigEnvelopedSignatureTransform env = new();
        reference.AddTransform(env);

        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);

        // Compute the signature.
        signedXml.ComputeSignature();

        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml();

        // Append the element to the XML document.
        xmlDoc.DocumentElement?.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
    }
}
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml
Imports System.Xml

Module SignXML
    Sub Main(ByVal args() As String)
        Try
            ' Create a new CspParameters object to specify
            ' a key container.
            Dim cspParams As New CspParameters With {
                .KeyContainerName = "XML_DSIG_RSA_KEY"
            }
            ' Create a new RSA signing key and save it in the container. 
            Dim rsaKey As New RSACryptoServiceProvider(cspParams)
            ' Create a new XML document.
            ' Load an XML file into the XmlDocument object.
            Dim xmlDoc As New XmlDocument With {
                .PreserveWhitespace = True
            }
            xmlDoc.Load("test.xml")
            ' Sign the XML document. 
            SignXml(xmlDoc, rsaKey)

            Console.WriteLine("XML file signed.")

            ' Save the document.
            xmlDoc.Save("test.xml")
        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try
    End Sub

    ' Sign an XML file. 
    ' This document cannot be verified unless the verifying 
    ' code has the key with which it was signed.
    Sub SignXml(ByVal xmlDoc As XmlDocument, ByVal rsaKey As RSA)
        ' Check arguments.
        If xmlDoc Is Nothing Then
            Throw New ArgumentException(
                "The XML doc cannot be nothing.", NameOf(xmlDoc))
        End If
        If rsaKey Is Nothing Then
            Throw New ArgumentException(
                "The RSA key cannot be nothing.", NameOf(rsaKey))
        End If
        ' Create a SignedXml object.
        Dim signedXml As New SignedXml(xmlDoc)
        ' Add the key to the SignedXml document.
        signedXml.SigningKey = rsaKey
        ' Create a reference to be signed.
        Dim reference As New Reference()
        reference.Uri = ""
        ' Add an enveloped transformation to the reference.
        Dim env As New XmlDsigEnvelopedSignatureTransform()
        reference.AddTransform(env)
        ' Add the reference to the SignedXml object.
        signedXml.AddReference(reference)
        ' Compute the signature.
        signedXml.ComputeSignature()
        ' Get the XML representation of the signature and save
        ' it to an XmlElement object.
        Dim xmlDigitalSignature As XmlElement = signedXml.GetXml()
        ' Append the element to the XML document.
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, True))
    End Sub
End Module

編譯程式碼

.NET 安全性

絕對不要以純文字儲存或傳輸非對稱金鑰組的私密金鑰。 如需對稱和非對稱密碼編譯金鑰的詳細資訊,請參閱產生加密和解密金鑰

絕對不要直接將私密金鑰內嵌在您的原始程式碼。 內嵌的金鑰可以藉由使用 Ildasm.exe (IL 反組譯工具) 或是藉由在文字編輯器 (例如記事本) 中開啟組件,輕鬆地從組件讀取。

另請參閱