XML Signature規範是將數字簽名和XML組合而成的產物,不要以為XML Signature僅僅是將數字簽名技術應用於XML文件。
XML Signature包括以下的功能:
- XML Signature可以對任何能夠以URI形式(uniform resource identifier)定位的資源做簽名。既包括與簽名同在一個XML文件中的元素,也包括其他XML文件中的元素,甚至可以是非XML形式的資源(比如一個圖形文件),只要能被URI定位到的資源都可以應用XML Signature. 這也代表了XML簽名的對象可以是動態的變化。
- XML Signature可以對XML文件中的任一元素做簽名,也可以對整個文件做簽名。
- XML Signature 既可以用非對稱密鑰做簽名(Digital Signature),也可以用對稱密鑰做簽名(HMAC)。
XML Signature的結構如下:
Java代碼
- <Signature>
- <SignedInfo>
- <CanonicalizationMethod>
- <SignatureMethod>
- (<Reference (URI=)? >
- (Transforms)?
- (DigestMethod)
- (DigestValue)
- </Reference>)+
- </SignedInfo>
- <SignatureValue>
- (KeyInfo)?
- (Object)*
- </Signature>
-
- (x)? 代表x出現0-1次 (x)+ 代表x出現1-n次 (x)* 代表x出現0-n次
下面對Signature中出現的各個元素做簡要介紹:
- SignedInfo表示最終要被簽名的對象,簽名主要包括兩個過程先對要簽名的對象做摘要,然後加密摘要(DSA不是加密摘要而是將摘要和密鑰混合,效果類似)。XML Signature簽名的對象並不僅僅是你引用的對象,而是包含了一些其他元素,比如CanonicalizationMethod, SignatureMethod元素,它是對整個SignedInfo元素做的簽名。
- CanonicalizationMethod代表了將XML元素標準化的方法,在XML的簽名中與通常的簽名有一個不同的地方在於XML元素的特殊性,比如同樣一份XML文件在Windows下的表示方法和Linux下就會有所不同,因為同樣一個換行符號在不同的操作系統代表的字符是不同的,但你不可能因為這個就認為這份XML文件被修改了;一個XML元素的兩個屬性的位置調換了,也不代表這份XML文件的完整性被破壞,所以在XML元素被簽名前需要做一個標準化的處理。該元素就是指定其處理方法。
- SignatureMethod指定了用於簽名的方法,其中包括了摘要所用的方法以及是使用非對稱密鑰還是對稱密鑰加密(或混合)。
- Reference表示真正想要簽名的對象,通過URI定位到要簽名的對象(一個xml元素或其他),如果沒有指定URI就表示要簽名的整個XML文件。
- Transforms表示了在簽名前可能對被簽名對象所要做的轉換,比如當待簽名的對象是一個二進制資源時,為了避免該對象中可能出現非法的XML格式,就需要用Base-64將其轉換一下。這裡還可以使用一些其他的轉化方法如XPATH和XSLT。
- DigestMethod指定了對引用對象做摘要的方法,一般使用SHA1。
- DigestValue這裡面存放做完摘要後的結果,這樣當後面對做SignedInfo簽名的時候就間接的對引用對象做了簽名,從而保證其完整性。
- SignatureValue這裡存放的是對SignedInfo元素標準化(CanonicalizationMethod)後簽名(SignatureMethod)的結果。
- KeyInfo是一個可選項,它用於消息接受方查找驗證簽名時所需的密鑰,比如用某個特定的名稱標識(Identity)來表示密鑰,這樣信息的接受方就可以根據這個標識來查找驗證簽名時所需要的密鑰。如果消息交換雙方之前已經約定好了簽名的密鑰就可以省略該元素。
- Object用於定義一些擴展信息,也是可選項。
其中根據被簽名對象(Reference中URI所指向的對象)和Signature元素所處的位置關係,將XML Signature做了一個分類。
如果被簽名對象是Signature的子元素那麼這個簽名屬於Enveloping Signatures類型。如果Signature是被簽名對象的子元素,那麼該簽名屬於Enveloped Signatures類型。如果以上兩種都不是則屬於Detached Signatures類型。
Java代碼
- Enveloping Signatures:
- <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
- <SignedInfo>
- <Reference URI="#111" />
- </SignedInfo>
- <SignatureValue>...</SignatureValue>
- <KeyInfo>...</KeyInfo>
- <Object>
- <SignedItem id="111">Stuff to be signed</SignedItem>
- </Object>
- </Signature>
-
-
- Enveloped Signatures:
- <PurchaseOrder id="po1">
- <SKU>125356</SKU>
- <Quantity>17</Quantity>
- <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
- <SignedInfo>
- <Reference URI="#po1" />
- </SignedInfo>
- <SignatureValue>...</SignatureValue>
- <KeyInfo>...</KeyInfo>
- </Signature>
- </PurchaseOrder>
-
-
- Detached Signatures 1:
- <PurchaseOrderDocument>
- <PurchaseOrder id="po1">
- <SKU>12366</SKU>
- <Quantity>17</SKU>
- </PurchaseOrder>
- <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
- <SignedInfo>
- <Reference URI="#po1" />
- </SignedInfo>
- <SignatureValue>...</SignatureValue>
- <KeyInfo>...</KeyInfo>
- </Signature>
- </PurchaseOrderDocument>
-
-
- Detached Signatures 2:
- <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
- <SignedInfo>
- <Reference URI="http://www.foo.com/picture.jpg" />
- </SignedInfo>
- <SignatureValue>...</SignatureValue>
- <KeyInfo>...</KeyInfo>
- </Signature>
在瞭解了XML Signature的結構的基礎上,再來看看XML Signature的處理過程,其中包括了Signature的創建以及驗證過程。
在創建Signature的時候分為兩個步驟:
1. 引用(Reference)的創建
1.1 利用URI定位到引用的資源,並獲得其數據。
1.2 利用Transforms元素中指定的方法對引用的資源做轉換。
1.3 利用DigestMethod元素中指定的方法對轉換後的資源做摘要,獲得的結果用於創建DigestValue元素。
1.4 將以上元素組合成Reference元素。
Java代碼
- <Reference URI="http://www.foo.com/securePage.html">
- <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
- <DigestValue>60NvZvtdTB+7UnlLp/H24p7h4bs=</DigestValue>
- </Reference>
2. 簽名(Signature)的創建
2.1 創建SignedInfo元素,並指定CanonicalizationMethod 和SignatureMethod的方法,然後將之前創建的Reference元素包含進來。
2.2 根據指定的CanonicalizationMethod將剛創建的SignedInfo元素標準化。
2.3 根據指定的SignatureMethod對標準化後的SignedInfo元素做簽名,所得到的結果用於創建SignatureValue元素。
2.4 將SignedInfo,SignatureValue以及可選的KeyInfo和Object元素組合成Signature元素。
經過以上步驟,Signature創建完畢。最後介紹消息的接受方如何對Signature進行驗證,從而確認消息的完整性。
Signature的驗證過程和創建過程一樣也分為兩個步驟,只有當Reference, Signature都通過驗證才能保證消息的完整性。首先在驗證前利用CanonicalizationMethod元素中指定的方法將整個Signature元素標準化,然後開始驗證各個部分:
1. 引用(Reference)的驗證
1.1 利用URI定位到引用的資源,並獲得其數據。
1.2 利用Transforms元素中指定的方法對引用的資源做轉換。
1.3 利用DigestMethod元素中指定的方法對轉換後的資源做摘要。
1.4 將上一步的結果與DigestValue中的內容做比較,如果完全一致,則通過驗證。
2. 簽名(Signature)的驗證
2.1 獲得用於驗證的密鑰。(可能事先已經約定好,也可能通過KeyInfo中的信息取得)
2.2 對經過標準化的SignedInfo元素做摘要。
2.3 利用在第一步中獲得的密鑰解密SignatureValue元素中的內容,將其與上一步創建的摘要做比較,如果完全一致,則通過驗證。如果使用了數字簽名(非對稱密鑰),那麼消息還將具有抗否認性。
當以上的兩個驗證都通過時,可以得到以下的結論:
1. 消息在傳送以及保存的過程中都沒有被別人算改。
2. 消息的發送方與簽名方一致(身份鑒別)。 因為密鑰只有消息的發送方和消息的接受方知道。
3. 如果使用了數字簽名(非對稱密鑰加密摘要), 那麼還可以防止消息的發送方否認它曾經發送過此消息。
然而以上的消息都是以明文形式傳遞的,為了保證消息的機密性,就引出了下面將要介紹的內容--- XML Encryption。
參考資料:<<Securing Web Services with WS-Security>>