天天看點

了解 Web 服務規範: 第 4 部分:WS-Security

開始之前

在本教程中,您将了解有關 Web 服務安全性(Web Services Security,WS-Security)的資訊。本教程針對這樣的開發人員,他們希望在能夠保證消息傳遞時不被篡改的環境中公開自己的服務,或在必須積極辨別消息發送方的情況下公開自己的服務。術語“WS-Security”通常指處理加密和數字簽名的一組規範,支援您建立安全應用程式。

為了按照本教程中的步驟進行操作,您應該具有 SOAP 的基本知識(可以通過閱讀本系列教程的第 1 部分了解 SOAP)和 XML 的基本知識。SOAP 與程式設計語言無關,但本教程中的示例使用的是 Java ™ 和 Apache Axis2 項目。不過,其中的概念也适用于任何程式設計語言和環境。

關于本系列

本系列教程以假想的報社 Daily Moon 為例,為了提高在競争激烈的環境中的工作效率,其員工将使用各種 Web 服務來建立工作流系統,我們将在此過程中講述各個 Web 服務基本概念。

第 1 部分說明了 Web 服務背後的基本概念,并示範了如何使用 SOAP(後續教程讨論的大部分内容的基礎規範)來将 Classifieds Department 連接配接到内容管理系統。

第 2 部分進一步深入說明如何使用 Web 服務描述語言(Web Services Description Language,WSDL)定義 Web 服務預期産生的消息,進而使團隊更友善地建立服務以及連接配接到服務的客戶機。

在第 3 部分中,團隊希望準備一系列服務,并希望能友善地查找這些服務。與此對應,統一描述、發現和內建(Universal Description, Discovery and Integration,UDDI)提供了可用服務的可搜尋注冊中心,以便将自己的服務釋出給其他人。

現在,在第 4 部分中,The Daily Moon 的發行人 Rudy 決定報社需要為通路其内部系統的 Web 服務制訂更好的安全過程。

在有關 WS-Policy 的第 5 部分中,我們将讨論團隊為了通路這些剛提供了安全保護的服務需要進行哪些更改。

第 6 部分重點讨論的将是互操作性,因為必須從單個系統通路來自幾個不同實作的服務。第 6 部分還将讨論在 WS-I 證書中涉及的要求和測試。

最後,第 7 部分将示範如何使用業務流程執行語言(Business Process Execution Language,WS-BPEL)來從各個服務建立複雜應用程式。

接下來讓我們更為詳細了解一下本教程中将讨論的内容。

閱讀本系列所有文章。

回頁首

關于本教程

在本教程中,您将了解 The Daily Moon 報社團隊如何使用 WS-Security 規範來保證本系列前面的教程中讨論的 Web 服務之一的安全。

在本教程中,您将了解以下内容:

  • 什麼是 WS-Security
  • 對稱和非對稱加密間的差異
  • 簽名和加密間的差異
  • 安全性對 SOAP 消息的影響
  • 如何使用 Axis2 保護 SOAP Web 服務的安全

在開始進行相關工作前,您将需要獲得一些工具。

回頁首

先決條件

本教程的大部分内容都是概念性的東西,但為了處理建立 SOAP 消息的代碼,您将需要安裝以下軟體:

我們将示範 Apache Geronimo 的安裝和用法,而此應用伺服器也是 IBM 的 WebSphere Community Edition 的基礎。還可以使用 WebSphere Application Server 等其他應用伺服器。可以下載下傳 Apache Geronimo。有關安裝 Geronimo 的更多資訊,請參見本系列的第 1 部分。

您将使用的是 Apache Axis2,其中包含了各種 SOAP 相關的 API,可極大地簡化您的工作。可以從 Apache.org 下載下傳 Apache Axis2。本教程使用的是 0.94 版,但應該也能使用更高版本。

Apache Axis2 Rampart 子產品——Security for the Axis2 Web 服務引擎通過 Rampart 子產品提供,而此子產品并未包含在預設安裝中。請從 Apache Download Mirrors 下載下傳此子產品。

Apache WSS4J——盡管 Axis 本身将使用 Rampart,但在某些情況下,您将需要引用 WSS4J 類目錄。請下載下傳 WSS4J 程式包。

Java 2 Standard Edition 的 1.4.2 或更高版本——所有這些工具都是基于 Java 的,本教程中将要建構的服務和客戶機也是如此。請下載下傳 J2SE SDK。

TCPMon(可選)——如果能實際看到消息,則更容易了解 Web 服務應用程式内的運作情況。請下載下傳 TCP Monitor,以檢視進出 Web 服務的消息。

GnuPG(可選)——我們将進行的所有消息簽名工作都由 Axis2 和 Java 本身進行,不過,如果希望逐個對文檔進行簽名處理(我們将對此進行簡單的示範),則請下載下傳 GnuPG。

您将還需要 Web 浏覽器和文本編輯器。

概述

在讨論如何保護服務的安全前,具體了解組成服務的各個部分可幫助确定必須進行哪些工作。

已完成的工作

本系列教程逐漸說明了 Daily Moon 報社的員工的探索過程,發現了采用 Web 服務形式工作的新方法。首先從 Classifieds Department 開始,該部門決定允許其他人通過使用 SOAP 消息(可以通過 HTTP 發送的 XML 消息)通路其系統。

例如,“for sale”子類别中的分類廣告數量的請求可能與清單 1 所示類似。

清單 1. 示例 SOAP 消息

<?xml version='1.0' ?><env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope">  <env:Header> </env:Header> <env:Body>  <cms:getNumberOfArticles xmlns:cms="http://www.daily-moon.com/cms">    <cms:category>classifieds</cms:category>    <cms:subcategory>forsale</cms:subcategory>  </cms:getNumberOfArticles> </env:Body></env:Envelope>
           

整個消息稱為信封,其内容由 Header 和主體組成。Header 包括有關消息本身的資訊(如路由資訊)或要由位于發送方和最終接收方之間可能對消息進行處理的“SOAP 中間層”或服務處理的資訊。(在這種情況下,可以參見任何 Header,但這正是即将放置我們的安全資訊的位置。)消息的主體包括“有效負載”,其中含有要傳遞給 Web 服務的實際資料。

在本例中,有效負載為 

getNumberOfArticles

 元素及其内容。

該報社的 IT 部門的 Gene 和 Frances 建立了一個處理 Web 服務請求的系統和用于發現和自動為服務建立客戶機的基礎設施。現在,該報社的發行人 Rudy 堅持要他們找到一種方法來防止對這些系統的非授權通路。

回頁首

安全性需求

基礎 SOAP 規範并不是針對保護消息安全而提供的,而将這個任務留給了擴充規範。困難之處源自 Web 服務應用程式本身的特性。在大多數情況下,我們都使用 SOAP over HTTP,這意味着每個消息都必須經過一個或多個中間節點,其中的任何節點都可以讀取和/或更改消息。而這假定的是 SOAP 請求本身是直接的請求。在某些情況下,SOAP 消息專門設計為要通過多個節點才能達到其最終的目的地。

最終的結果是,我們需要防止确定的接收方之外的其他人讀取敏感資訊,進而防止竊聽。我們還需要防止确定的發送方之外的其他人發送消息,以防止未授權的通路。

SOAP 規範提供了添加安全性資訊的方法——我們可将資訊添加到信封的 Header 元素中——但并沒有指定該資訊應該是什麼樣的。為了處理此問題,我們需要使用 WS-Security。

回頁首

WS-Security 的内容

在保證 SOAP 消息交換的安全方面存在三個主要問題,而 WS-Security 提供了解決所有這些問題的答案,但并不是直接方法。事實上,規範并不考慮如何保護消息,而是讨論如何讓接收方知道您在如何保護消息。為了進行實際的保護工作,WS-Security 引用了其他的規範。接下來讓我們看看如何進行此工作。

第一個問題是對客戶機進行辨別和身份驗證。由于存在很多種建立安全令牌的不同方法,是以 WS-Security 并未指定任何特定的方法,而是定義了應如何在 SOAP 消息中傳輸不同的安全标記。也就是說,它讓接收方知道如何從消息中提取安全令牌來進行處理。

第二個問題是確定消息的完整性。WS-Security 使用數字簽名處理此任務,它并沒有自己提出一個全新的東西,而是采用了 XML Signature 規範。XML Signature 是一項 W3C 建議規範,提供了對 XML 文檔進行數字簽名的機制。

第三個問題是保護消息在傳遞過程中不被竊聽。同樣,WS-Security 采用了另一個 W3C 标準,即 XML Encryption;此标準提供了對 XML 文檔進行加密的機制。

在本教程中,通過 Gene 和 Frances 進行相應的工作來保護現有 Classifieds 服務的過程,我們将了解如何使用這些标準來影響所使用的實際 SOAP 消息。

回頁首

目前服務

在我們讨論如何進行更改前,最好了解一下 Gene 和 Frances 面臨的現狀。Classifieds 的服務是使用 Axis2 實作的,而這意味着它包含在 *.aar 檔案中。CMSService.aar 檔案包含三個檔案,如清單 2 中所示。

清單 2. 原始服務的内容

CMSService.classmeta-inf/Manifest.MFmeta-inf/services.xml
           

此類本身相當簡單,接受一個列出類别的 SOAP 消息,并傳回包含該類别的廣告數量的 SOAP 消息。它将按照 services.xml 檔案(請參見清單 3)所定義的方式執行此功能。

清單 3. 原始 services.xml 檔案

<service name="CMSService">    <description>        This is a sample Web Service for the newspaper's         Content Managment System.    </description>    <parameter name="ServiceClass"                locked="false">CMSService</parameter>    <operation name="getNumberOfArticles">        <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>    </operation></service>
           

保護服務的安全僅涉及到對 services.xml 檔案進行處理;Gene 和 Frances 完全不必接觸實際的 Java 類。

回頁首

目前客戶機

客戶機本身相當簡單,僅發出并顯示請求,如清單 4 中所示:

清單 4. 原始客戶機類

import org.apache.axis2.Constants;import org.apache.axis2.addressing.EndpointReference;import org.apache.axis2.client.Options;import org.apache.axis2.client.ServiceClient;import org.apache.axiom.om.OMElement;import org.apache.axiom.om.OMAbstractFactory;import org.apache.axiom.soap.SOAPFactory;import org.apache.axiom.om.OMNamespace;import org.apache.axis2.context.ConfigurationContext;import org.apache.axis2.context.ConfigurationContextFactory;public class ClassifiedClient {    private static EndpointReference targetEPR =            new EndpointReference(               "http://localhost:8888/axis2/services/CMSService");    public static OMElement getNumOfArticlesOMElement() {        SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();        OMNamespace omNs = fac.createOMNamespace(                "http://daily-moon.com/cms", "cms");        OMElement method = fac.createOMElement("getNumberOfArticles",                                                omNs);        OMElement value = fac.createOMElement("category", omNs);        value.addChild(fac.createOMText(value, "classifieds"));        method.addChild(value);        return method;    }    public static void main(String[] args) {        try {            OMElement payload =                ClassifiedClient.getNumOfArticlesOMElement();              Options options = new Options();            options.setTo(targetEPR);            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);            ServiceClient sender = new ServiceClient();            sender.setOptions(options);            OMElement result = sender.sendReceive(payload);            String response = result.getText();            System.out.println("There are "+response+                               " classifieds at the moment.");        } catch (Exception e) {                 System.out.println(e.toString());        }    }}
           

請注意,Gene 已将端點端口更改為 8888,而不是 Geronimo 所偵聽的 8080 端口。他之是以這樣做,是為了插入其他步驟,以便能看到往返傳遞的消息。

回頁首

檢視消息

為了檢視實際的 SOAP 消息,請從 http://ws.apache.org/commons/tcpmon/download.cgi 下載下傳 TCPMon。(Axis2 提供了 SOAPMonitor,但 Gene 發現除了設定方面的麻煩以外,它僅顯示 SOAP,卻沒有顯示必要的原始消息,而後者正是我們希望檢視的内容。)

下載下傳後,請解壓縮應用程式,并運作 

tcpmon-1.0-bin\build\tcpmon.bat

 檔案。單擊 Admin 頁籤,并建立新偵聽器,如圖 1 中所示。

圖 1. TCPMon 的 Admin 頁籤

選擇 8888 作為要偵聽的端口,并指定 8080 為目标端口,以便使 TCPMon 位于客戶機和伺服器之間。單擊 Add,然後單擊 Port 8888 頁籤。單擊 XML Format 複選框。現在,當 Frances 運作客戶機時,Gene 可以看到請求和響應,如圖 2 中所示。

圖 2. 原始請求和響應

在繼續之前,讓我們簡單看一下實際的消息,以便了解進行了哪些更改。

回頁首

消息

消息本身非常簡單。請求僅請求系統中歸類廣告的數量,如清單 5 中所示:

清單 5. 原始請求

<?xml version='1.0' encoding='UTF-8'?>   <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">      <soapenv:Header />      <soapenv:Body>         <cms:getNumberOfArticles                     xmlns:cms="http://daily-moon.com/cms">            <cms:category>classifieds</cms:category>         </cms:getNumberOfArticles>      </soapenv:Body>   </soapenv:Envelope>
           

響應也同樣簡單,如清單 6 中所示:

清單 6. 原始響應

<?xml version='1.0' encoding='UTF-8'?>   <soapenv:Envelope xmlns:soapenv=           "http://schemas.xmlsoap.org/soap/envelope/">      <soapenv:Header />      <soapenv:Body>         <resp:numberOfArcticles                xmlns:resp="http://daily-moon.com/cms/"                 xmlns:tns="http://ws.apache.org/axis2"                            >42</resp:numberOfArcticles>      </soapenv:Body>   </soapenv:Envelope>
           

在這兩個消息中,Frances 将在 Header 元素中放入其他資訊,供伺服器(或客戶機)進行處理。

目前任何人都可以向服務發送請求并擷取響應,而這正是讓 Rudy 感到緊張的原因。他希望對服務進行設定,以使得隻有授權使用者才能獲得資訊,而競争者無法截取資訊。Rudy 指出這是一個不錯的概念驗證系統。他真正擔心的是更為複雜的系統,如向财務系統添加内容或進行通路的系統。但概念是相同的。

為了提供這個安全機制,Gene 和 Frances 需要使用加密及其相關技術——簽名。

加密和簽名

大部分安全性措施都涉及到某種形式的加密或數字簽名中的加密,是以在 Frances 讓 Gene 開始進行服務的安全配置前,她希望確定他們能了解自己即将進行的工作。

加密類型

加密是對資訊進行遮蔽以使其在沒有特殊知識的情況下不能閱讀的過程。已經出現了很多不同類型的加密方式。現代加密是應用于消息的定義良好的轉換序列和某種形式的“密鑰”。所得到的結果是無法閱讀的雜亂資料。解密是與此相反的過程,也涉及到密鑰,是以,通過将對密鑰進行保密,可以很好地確定其他人都不能閱讀經過加密的消息。現代加密方法可以根據是使用一個密鑰還是兩個密鑰來進行分類。

在對稱密鑰算法(例如,DES)中,發送方和接收方必須事先确定共享密鑰,并将其對其他各方保密;發送方使用此密鑰進行加密,而接收方使用相同的密鑰進行解密。在這種情況下,除了密鑰應該由且僅由涉及的雙方知道外,密鑰本身并不重要。

在非對稱密鑰算法(如 RSA)中,存在兩個分開的密鑰:公鑰向外公開,都知道其屬于某個特定的個人(或組織),而會将對應的私鑰保密。采用公鑰加密的消息僅能由私鑰進行解密,是以任何人都可以向特定個人發送保密消息。但反過來也成立,是以可使用某人的公鑰解密的消息一定是由此人發出的。我們将說明這如何在對 SOAP 消息進行加密和簽名的過程中應用。

.

回頁首

對檔案進行加密

Gene 決定首先看看實際消息文本如何受加密影響。她首先從文本檔案 msg.txt 着手,此檔案僅包含一行内容,如清單 7 中所示。

清單 7. 目标文本

Hello, world!
           

為了簡單起見,他使用了免費的 GnuPG 程式來執行清單 8 中所示的指令。

清單 8. 加密指令

gpg.exe -c -a --cipher-algo 3DES msg.txt
           

此指令将使該程式使用對稱密鑰算法 3DES 來對檔案進行加密。程式會詢問 passphrase(Gene 輸入的是“password”),然後将生成檔案 msg.txt.asc。可以在清單 9 中看到此檔案的内容。

清單 9. 經過加密的檔案

-----BEGIN PGP MESSAGE-----Version: GnuPG v1.4.2.2 (MingW32)jA0EAgMCqFjZXeujyOJgySoKQ2qhpCpGERKpFn0iKms4kwjpI51BLcoTyH4p61YJkDAiRMbC6PfCBmg==G4EN-----END PGP MESSAGE-----
           

當然,沒有人能夠據此猜出原始文本。成功後,Gene 繼續處理數字簽名的問題。

回頁首

簽名如何工作

數字簽名使用加密技術,但簽名的目的不同。簽名不會對消息進行遮蔽,而是讓接收方相信兩個資訊的真實性:消息的發送方和消息本身。

它的工作方式是這樣的。發送方使用其私鑰對消息進行加密。此“簽名”将随後與原始消息一起發送到接收方。接收方嘗試驗證簽名,即使用發送方的公鑰對簽名進行解密,并将結果與原始消息進行比較。如果此過程成功完成,接收方可以確定發送方為消息的唯一發出者,因為除了發送方之外,沒有人具有其私鑰。而且,如果原始消息在傳輸過程中發生了更改,解密後的簽名将不會與其比對,是以成功的簽名驗證也意味着沒有對消息進行篡改。

通常發送方不會對整個消息進行簽名,而計算消息的一個“摘要”(使用加密散列函數),對此摘要進行簽名,并将其随未加密的消息一起傳遞。接收方計算所接收到的消息的摘要,并将其與解密得到的簽名摘要進行比較。這可提供相同的功能,但不會讓每個消息的大小是以而翻倍。(它還減少了建立和驗證簽名的處理時間。)

回頁首

對檔案簽名

成功後 Gene 大受鼓舞,決定對此進行實際應用。他要對之前進行了加密的 msg.txt 檔案進行數字簽名。由于通過 GnuPG 可友善地對檔案進行簽名,是以他将使用同一個軟體,不過稍後将使用不同的技術來建立實際應用程式所使用的密鑰。

第一步是使用清單 10 中的指令建立密鑰對。

清單 10. 生成密鑰對 

gpg.exe --gen-key
           

程式将詢問有關密鑰的很多問題,如 Gene 的姓名、電子郵件等等。他采用了預設密鑰參數(DSA 算法和 2048 位密鑰長度),并提供了姓名“Jon Dow”。此操作會将密鑰存儲在 Gene 的 home 檔案夾的密鑰存儲庫檔案中。

現在他可以對消息進行簽名了。他使用了清單 11 中所示的指令。

清單 11. 對文檔進行簽名

gpg.exe --clearsign -u "Jon Dow" msg.txt
           

此時,程式将詢問與“Jon Dow”的密鑰相關的密碼,然後生成 msg.txt.asc 檔案,如清單 12 中所示。

清單 12. 經過簽名的文檔

-----BEGIN PGP SIGNED MESSAGE-----Hash: SHA1Hello, world!-----BEGIN PGP SIGNATURE-----Version: GnuPG v1.4.2.2 (MingW32)iD8DBQFEhftF06oTl3UESDQRArHsAJ0bE2qUEeVb5IDz4gQuRCgOes6v7gCfQhbJl356yO+YTkJUJZx4KoTTzok==ld3Y-----END PGP SIGNATURE-----
           

接收到此消息的人将知道使用“Jon Dow”的公鑰對此簽名進行解密,對未加密的消息進行散列操作(使用 SHA1),然後對二者進行比較。

現在 Gene 和 Frances 已經了解了加密和簽名如何工作,就可以開始對實際服務進行保護了。

保護服務的安全

保護服務的安全涉及到一系列必須在發送首個安全消息前進行的步驟;雖然這些步驟都不特定于實際的 WS-Security 規範(不管團隊将用于生成消息的軟體如何),但它們非常重要,會以某種形式在任何 WS-Security 安裝中進行。

生成密鑰存儲庫

現在 Gene 已經了解了簽名和加密的應用,接下來需要開始準備團隊自己的安裝了。他需要首先建立密鑰存儲庫,其中将包括可能需要的所有私鑰-公鑰對。為此,他将使用随 JDK 一起提供的 keytool 應用程式。

為了建立新密鑰和生成密鑰存儲庫,他将執行以下指令,如清單 13 中所示。

清單 13. 建立密鑰對和密鑰存儲庫

>cd %JAVA_HOME%\bin>keytool -genkey -keystore mykeys.jks -alias geneEnter keystore password:  mykeystorepasswordWhat is your first and last name?  [Unknown]:  Gene TellurideWhat is the name of your organizational unit?  [Unknown]:  Information TechnologiesWhat is the name of your organization?  [Unknown]:  The Daily MoonWhat is the name of your City or Locality?  [Unknown]:  New YorkWhat is the name of your State or Province?  [Unknown]:  NYWhat is the two-letter country code for this unit?  [Unknown]:  USIs CN=Gene Telluride, OU=Information Technologies, O=The Daily Moon, L=New York, ST=NY, C=US correct?  [no]:  yesEnter key password for <gene>        (RETURN if same as keystore password):  mypassword
           

指令行告知工具生成密鑰對,并将其存儲在 mykeys.jks 檔案中。密鑰對的别名為 gene,進而讓我們能友善地對其進行引用。Frances 可以建立自己的密鑰,并将其存儲在相同的 mykeys.jks 檔案中。

現在他們已經準備好開始進行保護服務本身安全的相關工作。

回頁首

啟用安全性

将 WS-Security 添加到服務的第一步是在伺服器上啟用它。Apache Axis2(團隊在其上運作其服務的 Web 服務引擎)是采用子產品化方式建構的,相應的 WS-Security 子產品稱為 Rampart(有關下載下傳資訊,請參見先決條件)。下載下傳了 Rampart 後,将 rampart-1.0.mar 檔案放置在您的 Axis 安裝的 modules 目錄中。例如,Gene 的安裝的 modules 檔案夾位于 C:\SW\geronimo-1.0\config-store\32\war\WEB-INF\modules。

接下來,Gene 需要使得此子產品全局可用,因為在 Axis2 背景工作的“處理程式鍊”中,需要使其參與系統,然後才能将消息定向到特定服務。重新啟動 Geronimo,并從以下位置登入到 Axis2 管理頁:http://localhost:8080/axis2/axis2-admin/login。(使用者名為 admin,密碼為 axis2。)單擊 Engage Module/For all services,并選擇 rampart-1.0。單擊 Engage,如圖 3 中所示。

圖 3. 使 Rampart 子產品參與系統

您還可以通過将 Rampart 子產品添加到 axis2.xml 檔案中使其參與系統,正如我們在了解如何保護客戶機安全時将看到的一樣。

回頁首

在服務上設定安全性

現在已經配備了基礎設施,Frances 就可以開始對實際服務進行安全保護工作了。首先,她關閉了 Geronimo,因為她希望更新位于 CMSService.aar 存檔中的 services.xml 檔案。(還可以選擇更新并重新加載服務,但她選擇了直接更改存檔。)本教程的安裝中,*.aar 檔案位于以下位置:C:\SW\geronimo-1.0\config-store\32\war\WEB-INF\services\CMSService.aar,她對 services.xml 檔案更新,以要求使用時間戳,如清單 14 中所示。

清單 14. 向服務添加時間戳

<service name="CMSService">    <description>        This is a sample Web Service for the newspaper's         Content Managment System.    </description>    <parameter name="ServiceClass"                locked="false">CMSService</parameter>    <parameter name="InflowSecurity">       <action>            <items>Timestamp</items>       </action>    </parameter>    <parameter name="OutflowSecurity">       <action>            <items>Timestamp</items>       </action>    </parameter>     <operation name="getNumberOfArticles">        <messageReceiver class=         "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>    </operation></service>
           

Axis2 允許具體控制出入服務的消息流。在本例中,她告知 Web 服務引擎要求傳入消息包括時間戳,并會在傳回給客戶機的傳出消息中包括時間戳。

稍後我們将了解此更改對伺服器和客戶機間傳遞的消息的影響,但當 Frances 嘗試運作測試時,TCPMon 顯示伺服器傳回了錯誤,而不是預期的資訊,如清單 15 中所示。

清單 15. 缺少 Security Header

<?xml version='1.0' encoding='UTF-8'?>   <soapenv:Envelope          xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"          xmlns:wsa="http://www.w3.org/2005/08/addressing">      <soapenv:Header>         <wsa:ReplyTo>            <wsa:Address>              http://www.w3.org/2005/08/addressing/anonymous            </wsa:Address>         </wsa:ReplyTo>         <wsa:MessageID>            urn:uuid:1CA9E94A9C7FE9D5B311507328796251         </wsa:MessageID>         <wsa:Action>            http://www.w3.org/2005/08/addressing/fault         </wsa:Action>      </soapenv:Header>      <soapenv:Body>         <soapenv:Fault>            <faultcode>soapenv:Client</faultcode>            <faultstring>WSDoAllReceiver: Request does not                contain required Security header</faultstring>             <detail>               <Exception>org.apache.axis2.AxisFault: WSDoAllReceiver:                    Request does not contain required Security                    header at ...               </Exception>            </detail>         </soapenv:Fault>      </soapenv:Body>   </soapenv:Envelope>
           

此處重要的是,Frances 現在知道它已經在工作了;除非符合為服務配置的安全性要求,否則引擎就不會接受消息。

現在她可以着手處理客戶機了。

回頁首

保護客戶機的安全

從很多方面而言,客戶機也是一種伺服器,因為它也發送和接收 SOAP 消息,是以 Frances 保護客戶機的安全的第一步自然是将 rampart-1.0.mar 添加到客戶機安裝。為此,她首先建立了一個新目錄 <CLIENT_HOME>\axis-repo\modules,其中 <CLIENT_HOME> 為 ClassifiedClient.class 檔案所在的目錄。她随後将 rampart-1.0.mar 檔案添加到該目錄。她還建立了第二個目錄 <CLIENT_HOME>\axis-repo\conf,并在其中建立了一個新檔案 axis2.xml。此檔案包含清單 16 中所示的代碼。

清單 16. 原始 axis2.xml 檔案

<axisconfig name="AxisJava2.0">    <!-- Engage the security module -->    <module ref="ramart"/>        <parameter name="OutflowSecurity">      <action>        <items>Timestamp</items>      </action>    </parameter><!--    <parameter name="InflowSecurity">      <action>        <items>Timestamp</items>      </action>    </parameter> -->     <!-- ================================================= -->    <!-- Parameters -->    <!-- ================================================= -->    <parameter name="hotdeployment" locked="false">true</parameter>    <parameter name="hotupdate" locked="false">false</parameter>    <parameter name="enableMTOM" locked="false">true</parameter>    <!-- Uncomment this to enable REST support -->    <!--    <parameter name="enableREST" locked="false">true</parameter>-->    <parameter name="userName" locked="false">admin</parameter>    <parameter name="password" locked="false">axis2</parameter>    <!-- ================================================= -->    <!-- Message Receivers -->    <!-- ================================================= -->    <!--This is the Deafult Message Receiver for the system , if you want to have MessageReceivers for -->    <!--all the other MEP implement it and add the correct entry to here, so that you can refer from-->    <!--any operation -->    <!--Note : You can ovride this for particular service by adding the same element with your requirement-->    <messageReceivers>        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"                         class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"                         class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>    </messageReceivers>    <!-- ================================================= -->    <!-- Transport Ins -->    <!-- ================================================= -->    <transportReceiver name="http"                       class="org.apache.axis2.transport.http.SimpleHTTPServer">        <parameter name="port" locked="false">6060</parameter>        <!--If you want to give your own host address for EPR generation-->        <!--uncommet following paramter , and set as you required.-->        <!--<parameter name="hostname" locked="false">http://myApp.com/ws</parameter>-->    </transportReceiver>    <transportReceiver name="tcp"                       class="org.apache.axis2.transport.tcp.TCPServer">        <parameter name="port" locked="false">6061</parameter>        <!--If you want to give your own host address for EPR generation-->        <!--uncommet following paramter , and set as you required.-->        <!--<parameter name="hostname" locked="false">tcp://myApp.com/ws</parameter>-->    </transportReceiver>    <!-- ================================================= -->    <!-- Transport Outs -->    <!-- ================================================= -->    <transportSender name="tcp"                     class="org.apache.axis2.transport.tcp.TCPTransportSender"/>    <transportSender name="local"                     class="org.apache.axis2.transport.local.LocalTransportSender"/>    <transportSender name="jms"                     class="org.apache.axis2.transport.jms.JMSSender"/>    <transportSender name="http"                     class="org.apache.axis2.transport.http.CommonsHTTPTransportSender">        <parameter name="PROTOCOL" locked="false">HTTP/1.1</parameter>        <parameter name="Transfer-Encoding" locked="false">chunked</parameter>    </transportSender>    <transportSender name="https"                     class="org.apache.axis2.transport.http.CommonsHTTPTransportSender">        <parameter name="PROTOCOL" locked="false">HTTP/1.1</parameter>        <parameter name="Transfer-Encoding" locked="false">chunked</parameter>    </transportSender>    <!-- ================================================= -->    <!-- Phases  -->    <!-- ================================================= -->    <phaseOrder type="inflow">        <!--  System pre defined phases       -->         <phase name="Transport">            <handler name="RequestURIBasedDispatcher"                     class="org.apache.axis2.engine.RequestURIBasedDispatcher">                <order phase="Dispatch"/>            </handler>            <handler name="SOAPActionBasedDispatcher"                     class="org.apache.axis2.engine.SOAPActionBasedDispatcher">                <order phase="Dispatch"/>            </handler>        </phase>        <phase name="Security"/>        <phase name="PreDispatch"/>        <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">            <handler name="AddressingBasedDispatcher"                     class="org.apache.axis2.engine.AddressingBasedDispatcher">                <order phase="Dispatch"/>            </handler>            <handler name="SOAPMessageBodyBasedDispatcher"                     class="org.apache.axis2.engine.SOAPMessageBodyBasedDispatcher">                <order phase="Dispatch"/>            </handler>            <handler name="InstanceDispatcher"                     class="org.apache.axis2.engine.InstanceDispatcher">                <order phase="PostDispatch"/>            </handler>        </phase>        <!--  System pre defined phases       -->        <!--   After Postdispatch phase module author or or service author can add any phase he want      -->        <phase name="OperationInPhase"/>    </phaseOrder>    <phaseOrder type="outflow">        <!--      user can add his own phases to this area  -->        <phase name="OperationOutPhase"/>        <!--system predefined phase-->        <!--these phase will run irrespective of the service-->        <phase name="PolicyDetermination"/>        <phase name="MessageOut"/>    </phaseOrder>    <phaseOrder type="INfaultflow">        <phase name="PreDispatch"/>        <phase name="Dispatch" class="org.apache.axis2.engine.DispatchPhase">            <handler name="RequestURIBasedDispatcher"                     class="org.apache.axis2.engine.RequestURIBasedDispatcher">                <order phase="Dispatch"/>            </handler>            <handler name="SOAPActionBasedDispatcher"                     class="org.apache.axis2.engine.SOAPActionBasedDispatcher">                <order phase="Dispatch"/>            </handler>            <handler name="AddressingBasedDispatcher"                     class="org.apache.axis2.engine.AddressingBasedDispatcher">                <order phase="Dispatch"/>            </handler>            <handler name="SOAPMessageBodyBasedDispatcher"                     class="org.apache.axis2.engine.SOAPMessageBodyBasedDispatcher">                <order phase="Dispatch"/>            </handler>            <handler name="InstanceDispatcher"                     class="org.apache.axis2.engine.InstanceDispatcher">                <order phase="PostDispatch"/>            </handler>        </phase>        <!--      user can add his own phases to this area  -->        <phase name="OperationInFaultPhase"/>    </phaseOrder>    <phaseOrder type="Outfaultflow">        <!--      user can add his own phases to this area  -->        <phase name="OperationOutFaultPhase"/>        <phase name="PolicyDetermination"/>        <phase name="MessageOut"/>    </phaseOrder>    </axisconfig>
           

此代碼中的大部分都是樣本,摘自其他 Axis2 示例。不過,在頂部的粗體部分,Frances 添加了特定的代碼來告知客戶機發送給伺服器的消息添加時間戳。她選擇不處理伺服器傳回的時間戳(至少目前如此)。不過,與服務不同,客戶機不會自動遵循這些指令。她必須對實際類進行更改。

回頁首

對客戶機類的更改

為了客戶機類進行 axis2.xml 檔案中指定的更改,它必須能夠識别這些内容。為此,Frances 将相應的配置添加到了 

ServiceClient

的建立過程中,如清單 17 中所示。

清單 17. 從 ClassifiedClient.java 調用新配置

...    public static void main(String[] args) {        try {            OMElement payload =                 ClassifiedClient.getNumOfArticlesOMElement();            ConfigurationContext                  configContext = ConfigurationContextFactory                      .createConfigurationContextFromFileSystem(                                               "axis-repo", null);             Options options = new Options();            options.setTo(targetEPR);            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);            ServiceClient sender =                   new ServiceClient(configContext, null);            sender.setOptions(options);            OMElement result = sender.sendReceive(payload);            String response = result.getText();            System.out.println("There are "+response+                                  " classifieds at the moment.");        } catch (Exception e) {                 System.out.println(e.toString());        }    }}
           

首先,Frances 建立一個新 

ConfigurationContext

,這将允許 

ServiceClient

 查詢新配置。但為了使其實際發生,她将需要更改自己調用實際客戶機類的方式。

回頁首

将其組合到一起

為了客戶機恰當地調用 Rampart 子產品,它需要知道在何處能找到配置檔案以及任何其他存儲庫項目(如 *.mar 檔案本身)。為此,Frances 向腳本添加了更多的細節,以設定類路徑和運作客戶機類,如清單 18 中所示。

清單 18. 調用類

echo offSET CLASSPATH=C:/SW/axis2/lib/XmlSchema-1.0.2.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axiom-api-1.0.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axiom-impl-1.0.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axis2-kernel-1.0.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-codec-1.3.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-httpclient-3.0.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-logging-1.0.4.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/                             geronimo-spec-activation-1.0.2-rc4.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/                             geronimo-spec-javamail-1.3.1-rc5.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/jaxen-1.1-beta-8.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/log4j-1.2.13.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/neethi-1.0.1.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/stax-api-1.0.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/wsdl4j-1.5.2.jarSET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/wstx-asl-2.9.3.jarSET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/wss4j-1.5.0.jarSET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/xmlsec-1.3.0.jarSET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/                             commons-discovery-0.2.jarSET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/                             bcprov-jdk13-132.jarSET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/xalan.jarSET CLASSPATH=%CLASSPATH%;.java.exe -Daxis2.xml=axis-repo/conf/axis2.xml          -Daxis2.repo=axis-repo ClassifiedClient
           

請注意,Frances 還添加多個來自 WSS4J 分發版本的 *.jar 檔案(有關下載下傳資訊,請參見先決條件)。

現在她已經準備好再次嘗試請求。

回頁首

請求

運作請求會顯示一條普通 SOAP 消息,但有一個例外,如清單 19 中所示。

清單 19. 帶時間戳的 SOAP 消息

<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv=      "http://schemas.xmlsoap.org/soap/envelope/">   <soapenv:Header>      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">         <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-29987161">            <wsu:Created>2006-06-19T16:22:28.578Z</wsu:Created>            <wsu:Expires>2006-06-19T16:27:28.578Z</wsu:Expires>         </wsu:Timestamp>      </wsse:Security>    </soapenv:Header>   <soapenv:Body>      <cms:getNumberOfArticles xmlns:cms="http://daily-moon.com/cms">         <cms:category>classifieds</cms:category>      </cms:getNumberOfArticles>   </soapenv:Body></soapenv:Envelope>
           

現在,Frances 首次在她的消息中看到了 Security Header。在本例中,它隻是一個時間戳,顯示消息建立的時間。mustUnderstand 屬性訓示,如果伺服器不知道如何處理此 Timestamp 元素,則必須拒絕此消息。

Timestamp 可能是最簡單的 WS-Security 元素。它們提供了限制消息生存期的方法,防止惡意者竊聽消息并自由更改後再将其發出。在這種情況下,Timestamp 會在建立消息後五秒鐘過期,是以如果消息存在時間超過此限制,則一定會拒絕此消息。(當然,惡意者仍然可以更改 Timestamp 值,但我們稍後将在讨論簽名時處理這個問題。)

回頁首

響應

正如服務中指定的,響應也具有時間戳,如清單 20 中所示。

清單 20. 響應

<?xml version='1.0' encoding='UTF-8'?>   <soapenv:Envelope xmlns:soapenv=            "http://schemas.xmlsoap.org/soap/envelope/">      <soapenv:Header>         <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">            <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-22347273">               <wsu:Created>2006-06-19T16:22:29.281Z</wsu:Created>               <wsu:Expires>2006-06-19T16:27:29.281Z</wsu:Expires>            </wsu:Timestamp>            <wsse11:SignatureConfirmation xmlns:wsse11="http://docs.oasis-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-secext-1.1.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SigConf-5759024" />         </wsse:Security>       </soapenv:Header>      <soapenv:Body>         <resp:numberOfArcticles                      xmlns:resp="http://daily-moon.com/cms/"                      xmlns:tns="http://ws.apache.org/axis2"                >42</resp:numberOfArcticles>      </soapenv:Body>   </soapenv:Envelope>
           

按指定的情況,響應包括時間戳,但也表明資訊已經過處理和驗證(盡管 Frances 尚未進行相應的配置來驗證這兩個方面)。

請注意,在這兩種情況下,實際消息都保持原樣。

對消息進行簽名

現在,Frances 已向傳出和傳入消息添加了時間戳,但并沒有防止直接更改其值并重新傳輸的機制。為了解決此問題(以及由于資訊被更改而導緻的任何其他問題),Frances 需要對其消息進行簽名。

消息簽名如何工作

正如您之前已經了解到的,對消息簽名涉及到以已知的方式建立已加密的資料的一個版本,以便能通過對其進行解密來提供能夠與原始值進行比較的值。例如,假定 Frances 希望對消息中的 Timestamp 元素進行數字簽名,以便伺服器能夠驗證其沒有被篡改或以某種方式盜用。

為此,她将制訂一個将進行若幹步驟的流程。

首先,她将對消息(或消息的一部分)進行簽名。為此,她将使用 axis2.xml 檔案來指定某個使用者作為簽名者。Axis2 将接受此資訊,并使用其進行兩個操作。首先,它将使用者别名提供給“回調類”,此類将傳回該使用者的密碼。獲得了此密碼後,Axis2 将随後從我們前面建立的密鑰存儲庫檢索使用者的私鑰。

通過使用此私鑰,Axis2 将對消息的相關部分進行加密(或簽名),并将簽名添加到消息中。它将随後發送此消息。當服務接收到消息時,它會進行幾乎完全相同的工作;它将通路密鑰存儲庫來擷取該使用者的公鑰,然後對簽名進行驗證。

請注意,如果服務要将經過簽名的内容發回,在傳回過程中,相應的角色将反過來。

讓我們了解一下如何完成這些工作。

回頁首

callback

 類

首先是建立 

callback

 類。在實際的情況中,此類可能通路 LDAP 目錄或使用其他方法将使用者名與密碼關聯,但 Frances 首先要進行概念驗證,是以她将建立簡單的 

callback

 類,在其中傳回任意值,如清單 21 中所示。

清單 21. PWCallback.java,

callback

 類

import org.apache.ws.security.WSPasswordCallback;import javax.security.auth.callback.Callback;import javax.security.auth.callback.CallbackHandler;import javax.security.auth.callback.UnsupportedCallbackException;import java.io.IOException;public class PWCallback implements CallbackHandler {   public void handle(Callback[] callbacks)            throws IOException, UnsupportedCallbackException {      for (int i = 0; i < callbacks.length; i++) {         if (callbacks[i] instanceof WSPasswordCallback) {            WSPasswordCallback pc=(WSPasswordCallback)callbacks[i];                if (pc.getIdentifer().equals("gene")) {                    pc.setPassword("mypassword");                } else if (pc.getIdentifer().equals("frances")) {                    pc.setPassword("francespassword");                } else {                    throw new UnsupportedCallbackException(                                   callbacks[i], "Unknown user");                }            } else {                throw new UnsupportedCallbackException(callbacks[i],                        "Unrecognized Callback");            }        }    }}
           

該類在 

handle()

 方法中進行的工作并不重要;重要的是它要麼在 

WSPasswordCallback

 對象上設定密碼,要麼引發異常。

回頁首

屬性檔案

接下來,Frances 必須找到一個方法來告知 Axis2 在何處尋找密鑰存儲庫以及哪個類應實際執行所有這些加密操作。為此,她建立了屬性檔案 security.properties,如清單 22 中所示:

清單 22. security.properties 檔案

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlinorg.apache.ws.security.crypto.merlin.keystore.type=jksorg.apache.ws.security.crypto.merlin.keystore.password=mykeystorepasswordorg.apache.ws.security.crypto.merlin.file=mykeys.jks
           

指定了提供者後,屬性檔案将定義存儲庫的類型(在本例中為随 Java 提供的專用格式 jks)、密鑰存儲庫的密碼以及實際密鑰存儲庫檔案的名稱(為了簡單起見,她将其放入了與客戶機類檔案相同的目錄中)。

回頁首

axis2.xml 檔案

現在她需要根據自己對傳出消息的設想設定 axis2.xml 檔案,如清單 23 中所示。

清單 23. 帶簽名的 axis2.xml 檔案

<axisconfig name="AxisJava2.0">    <!-- Engage the security module -->    <module ref="rampart"/>    <parameter name="OutflowSecurity">      <action>        <items>Signature</items>        <user>gene</user>                    <passwordCallbackClass>PWCallback</passwordCallbackClass>        <signaturePropFile>security.properties</signaturePropFile>        <signatureKeyIdentifier>SKIKeyIdentifier</signatureKeyIdentifier>        <signatureParts>{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body</signatureParts>      </action>    </parameter><!--    <parameter name="InflowSecurity">      <action>        <items>Timestamp</items>      </action>    </parameter>-->...
           

在本例中,它沒有告知客戶機添加時間戳,而是讓其添加一個簽名。看到此資訊後,客戶機将檢視 

signaturePropFile

 中指定的檔案,并使用其中找到的資訊——以及 

passwordCallbackClass

——來擷取 gene 使用者的密碼。從此處,它将擷取 gene 的密鑰,并進行對 

signatureParts

 元素中指定的消息部分進行簽名。在本例中即 Body 所表示的元素(而不是僅此元素的内容),此元素屬于 http://schemas.xmlsoap.org/soap/envelope/ 命名空間的一部分。

您可以對消息的任意部分進行簽名。例如,人們經常對 Timestamp 進行簽名(如果有)。

回頁首

請求

那麼,所有這些更改對客戶機産生的消息有何影響呢?您可以在清單 24 中看到所得到的請求。

清單 24. 經過簽名的請求

<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv=        "http://schemas.xmlsoap.org/soap/envelope/">   <soapenv:Header>      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">         <ds:Signature xmlns:ds="..." Id="Signature-8789796">            <ds:SignedInfo>               <ds:CanonicalizationMethod Algorithm=                    "http://www.w3.org/2001/10/xml-exc-c14n#" />               <ds:SignatureMethod Algorithm=                 "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />               <ds:Reference URI="#id-17764792">                  <ds:Transforms>                     <ds:Transform Algorithm=                    "http://www.w3.org/2001/10/xml-exc-c14n#" />                  </ds:Transforms>                  <ds:DigestMethod Algorithm=                     "http://www.w3.org/2000/09/xmldsig#sha1" />                  <ds:DigestValue                  >wg+9KsR6BVBiO/hakJJwMdtU7+I=</ds:DigestValue>               </ds:Reference>            </ds:SignedInfo> <ds:SignatureValue>hom9Enzu3yHBuaF...</ds:SignatureValue>            <ds:KeyInfo Id="KeyId-19475750">               <wsse:SecurityTokenReference xmlns:wsu=".."                       wsu:Id="STRId-31156635">                  <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>               </wsse:SecurityTokenReference>            </ds:KeyInfo>         </ds:Signature>      </wsse:Security>   </soapenv:Header>   <soapenv:Body xmlns:wsu="..." wsu:Id="id-17764792">      <cms:getNumberOfArticles xmlns:cms="http://daily-moon.com/cms">         <cms:category>classifieds</cms:category>      </cms:getNumberOfArticles>   </soapenv:Body></soapenv:Envelope>
           

我從中剔除了命名空間值,以提高其可讀性;接下來我們将對其詳細分析。

Security

 元素包含所有安全性資訊,當然,首先是簽名。簽名中首先是實際被簽名的資訊。向下跳一點,會看到 

Reference

 元素包含 

URI

 屬性,此屬性将向後引用 Body 的 

id

 屬性,即 Frances 讓客戶機進行簽名的部分。是以,服務可從此了解實際對什麼資訊進行了簽名。

後退一點,對内容簽名的第一步是對其進行規範化(移除無關文本節點等),但實際有兩種方法可用于進行此工作,即包含法和排除法,二者的差別在于每個方法如何處理命名空間聲明。是以,

CanonicalizationMethod

 元素指定簽名使用哪個方法。

我們再看看 

SignatureMethod

,顧名思義,其内容指定用于對相關資料進行簽名的方法。

Reference

 元素包括有關為了獲得要簽名的最終内容所需要進行的所有步驟的資訊,以便驗證過程能夠進行相同的步驟并獲得相同的

SignatureValue

KeyInfo

 提供用于對資料進行簽名的實際密鑰或對此密鑰的引用。

回頁首

對服務進行更改

現在客戶機将建立簽名,但服務并不知道如何處理此簽名。Frances 将要進行此更改工作。

實際上,服務需要執行很多與客戶機相同的步驟;它需要能夠在密鑰存儲庫中找到密碼和密鑰,是以 Frances 首先向 CMSService.aar 檔案添加 mykeys.jks、PWCallback.class 和 security.properties 檔案。并不一定要使用與客戶機相同的類和密鑰存儲庫,但在本例中,為了友善起見,她使用了相同的類和密鑰存儲庫。

她還向 Axis2 應用程式的 lib 目錄添加了 bcprov-jdk13-132.jar、wss4j-1.5.0.jar 和 xmlsec-1.3.0.jar。(這些檔案是随 WSS4J 分發版本一起提供的。)

Frances 随後必須設定服務定義(位于 services.xml 中),以便識别傳入的已簽名資料。她通過進行清單 25 中所示的更改實作了此任務。

清單 25. 告知服務将接收經過簽名的資料

<service name="CMSService">    <description>   This is a sample Web Service for the newspaper's Content Managment System.    </description>    <parameter name="ServiceClass" locked="false">CMSService</parameter>    <parameter name="InflowSecurity">       <action>            <items>Signature</items>            <passwordCallbackClass>PWCallback</passwordCallbackClass>            <signaturePropFile>security.properties</signaturePropFile>       </action>    </parameter>    <parameter name="OutflowSecurity">       <action>            <items>Timestamp</items>       </action>    </parameter>    <operation name="getNumberOfArticles">        <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>    </operation></service>
           

這些更改足以讓服務知道預期将接受什麼資料以及如何處理這些經過簽名的資料。

回頁首

響應

對應的響應是一個包括時間戳的文檔,與 

OutFlowSecurity

 參數指定的相符,但還包括有關簽名驗證的資訊,如清單 26 中所示。

清單 26. 響應

<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv=         "http://schemas.xmlsoap.org/soap/envelope/">   <soapenv:Header>      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">         <wsu:Timestamp xmlns:wsu="..." wsu:Id="Timestamp-27995990">            <wsu:Created>2006-06-19T23:56:55.214Z</wsu:Created>            <wsu:Expires>2006-06-20T00:01:55.214Z</wsu:Expires>         </wsu:Timestamp>         <wsse11:SignatureConfirmation xmlns:wsse11="..."              xmlns:wsu="..." Value="hom9Enzu3yHBuaigFl26b6A+5hy..."              wsu:Id="SigConf-25877728" />      </wsse:Security>   </soapenv:Header>   <soapenv:Body>      <resp:numberOfArcticles xmlns:resp="http://daily-moon.com/cms/"    xmlns:tns="http://ws.apache.org/axis2">42</resp:numberOfArcticles>   </soapenv:Body></soapenv:Envelope>
           

現在讓我們看看如何将加密添加到其中。

将加密添加到其中

Frances 對于使用簽名進行消息驗證的過程非常滿意,但仍然沒有辦法對資訊進行遮蔽,以防止競争者和其他人閱讀它。為此,她将必須将加密機制添加到應用程式中。

更改服務

這次她首先處理服務。她已經添加了應用程式所需的所有其他類,是以她隻需要更改 services.xml 檔案即可,如清單 27 中所示。

清單 27. 将加密機制添加到服務中

<service name="CMSService">    <description>        This is a sample Web Service for the newspaper's         Content Managment System.    </description>    <parameter name="ServiceClass"                locked="false">CMSService</parameter>    <parameter name="InflowSecurity">       <action>            <items>Timestamp Signature Encrypt</items>            <passwordCallbackClass>PWCallback</passwordCallbackClass>            <signaturePropFile>security.properties</signaturePropFile>       </action>    </parameter>    <operation name="getNumberOfArticles">        <messageReceiver class=        "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>    </operation></service>
           

此處 Frances 告知服務傳入的消息将具有一個添加的時間戳,它們已簽名,并且已加密——按照此順序。

現在她隻需要告知客戶機進行此工作即可。

回頁首

更改客戶機

由于已經打好了基礎,将加密機制添加到客戶機的過程也非常簡單,僅涉及到對 axis2.xml 檔案進行一個簡單的更改即可,如清單 28 中所示。

清單 28. 将加密機制添加到客戶機

<axisconfig name="AxisJava2.0">    <!-- Engage the security module -->    <module ref="rampart"/>        <parameter name="OutflowSecurity">      <action>        <items>Timestamp Signature Encrypt</items>        <user>gene</user>        <passwordCallbackClass>PWCallback</passwordCallbackClass>        <signaturePropFile>security.properties</signaturePropFile>        <signatureKeyIdentifier                        >SKIKeyIdentifier</signatureKeyIdentifier>        <encryptionKeyIdentifier                       >SKIKeyIdentifier</encryptionKeyIdentifier>        <encryptionUser>frances</encryptionUser>        <signatureParts>{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body</signatureParts>        <optimizeParts>//xenc:EncryptedData/xenc:CipherData/xenc:CipherValue</optimizeParts>      </action>    </parameter>    <!-- ================================================= -->    <!-- Parameters -->    <!-- ================================================= -->    <parameter name="hotdeployment" locked="false">true</parameter>...
           

請注意,Francis 為加密指定了不同的使用者,而不是用于進行數字簽名的使用者。并非必須這樣做,但可以采用這樣的方式。另請注意,添加了 

optimizeParts

 元素,以指定 Axis2 應如何在消息中表示經過加密的資料。

接下來讓我們看看其工作情況。

回頁首

請求

一切就緒後,消息将會變得有些複雜,如清單 29 中所示。

清單 29. 經過簽名、封裝和加密的請求

<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv=            "http://schemas.xmlsoap.org/soap/envelope/"         xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">   <soapenv:Header>      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">         <xenc:EncryptedKey Id="EncKeyId-229902">            <xenc:EncryptionMethod Algorithm=                 "http://www.w3.org/2001/04/xmlenc#rsa-1_5" />            <ds:KeyInfo xmlns:ds="...">               <wsse:SecurityTokenReference>                  <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">Xeg55vRyK3ZhAEhEf+YT0z986L0=</wsse:KeyIdentifier>               </wsse:SecurityTokenReference>            </ds:KeyInfo>            <xenc:CipherData>               <xenc:CipherValue>PpAOXj5P0W8ukm...</xenc:CipherValue>            </xenc:CipherData>            <xenc:ReferenceList>               <xenc:DataReference URI="#EncDataId-30957433" />            </xenc:ReferenceList>         </xenc:EncryptedKey>         <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"                        Id="Signature-17764792">            <ds:SignedInfo>               <ds:CanonicalizationMethod Algorithm=                      "http://www.w3.org/2001/10/xml-exc-c14n#" />               <ds:SignatureMethod Algorithm=                   "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />               <ds:Reference URI="#id-30957433">                  <ds:Transforms>                     <ds:Transform Algorithm=                      "http://www.w3.org/2001/10/xml-exc-c14n#" />                  </ds:Transforms>                  <ds:DigestMethod Algorithm=                       "http://www.w3.org/2000/09/xmldsig#sha1" />                  <ds:DigestValue>+ECkM6R4GQ7AQ=...</ds:DigestValue>               </ds:Reference>            </ds:SignedInfo>            <SignatureValue>DIeP5AxVmfw...</ds:SignatureValue>            <ds:KeyInfo Id="KeyId-16675983">               <wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-21866740">                  <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>               </wsse:SecurityTokenReference>            </ds:KeyInfo>         </ds:Signature>         <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-13665843">            <wsu:Created>2006-06-20T00:46:58.263Z</wsu:Created>            <wsu:Expires>2006-06-20T00:51:58.263Z</wsu:Expires>         </wsu:Timestamp>      </wsse:Security>   </soapenv:Header>   <soapenv:Body xmlns:wsu="..." wsu:Id="id-30957433">      <xenc:EncryptedData Id="EncDataId-30957433" Type=                "http://www.w3.org/2001/04/xmlenc#Content">         <xenc:EncryptionMethod Algorithm=           "http://www.w3.org/2001/04/xmlenc#aes128-cbc" />         <xenc:CipherData>            <xenc:CipherValue>DZ3vWPtabb5vBpZMlEYLPjFc8r2DMJ...fSjXpBFa7gybNA==</xenc:CipherValue>         </xenc:CipherData>      </xenc:EncryptedData>   </soapenv:Body></soapenv:Envelope>
           

首先看下面,請注意實際請求并不會出現,而 Axis2 将其替換為了一個 

EncryptedData

 元素,其中包括有關資料如何加密的資訊以及實際的經過加密的資料(在 

CypherData

 和 

CypherValue

 元素中)。

資料是使用共享密鑰加密的,這意味着消息中必須包含該密鑰,以便能對其進行解密。共享密鑰已使用接收方的公鑰加密,嵌入在

EncryptedKey

 元素的 Header 中。此密鑰也包括一個 

ReferenceList

,而後者包括了一個 

DataReference

,指回到使用此密鑰進行加密的資料。

是以,在另一方面,接收者(在此情況下為伺服器)将接收消息,使用自己的私鑰對共享密鑰進行解密,然後使用共享密鑰對消息的主體進行解密。

完成了一切工作後,響應又是什麼樣呢?

回頁首

響應

響應實際上相當簡單,因為 Frances 并未在伺服器上設定任何 

OutFlowSecurity

,如清單 30 中所示。

清單 30. 響應

<?xml version='1.0' encoding='UTF-8'?>   <soapenv:Envelope xmlns:soapenv=            "http://schemas.xmlsoap.org/soap/envelope/">      <soapenv:Header />      <soapenv:Body>         <resp:numberOfArcticles xmlns:resp=                "http://daily-moon.com/cms/" xmlns:tns=                "http://ws.apache.org/axis2"         >42</resp:numberOfArcticles>      </soapenv:Body>   </soapenv:Envelope>
           

這是一個完全有效的 SOAP 響應,但有一處例外。您可能記得,Frances 已将客戶機設定為預期會在自己的  

InFlowSecurity

  中包含至少一個時間戳。是以,盡管進行了所有這些工作,除非伺服器和客戶機都生成和期望相同的安全性方法,否則請求将仍然失敗。-

組合

此時 Frances 和 Gene 僅獲得了一些獨立的示例,是以他們決定将所有内容都放入到單個實作中,以向 Rudy 進行示範。

最終的服務規範

Rudy 希望服務僅接收來自授權個人(或實體)的請求,而且他不希望競争者能夠閱讀響應的内容。為此,Gene 和 Frances 進行了以下的工作:

  1. 客戶機将添加一個時間戳,以供使用經過認可的使用者的私鑰進行簽名時使用。這将處理授權通路的問題,防止對消息進行竊聽和重發。
  2. 伺服器會添加時間戳,但還将對響應進行加密,以防止竊聽者看到發送回去的資料。

讓我們看看這一切将如何工作。

服務

在服務端,Gene 按照清單 31 所示對 services.xml 檔案進行設定。

清單 31. 最終的 services.xml 檔案

<service name="CMSService">    <description>        This is a sample Web Service for the newspaper's         Content Managment System.    </description>    <parameter name="ServiceClass"                locked="false">CMSService</parameter>    <parameter name="InflowSecurity">       <action>            <items>Timestamp Signature</items>            <passwordCallbackClass>PWCallback</passwordCallbackClass>            <signaturePropFile>security.properties</signaturePropFile>       </action>    </parameter>    <parameter name="OutflowSecurity">      <action>        <items>Timestamp Signature Encrypt</items>        <user>gene</user>        <passwordCallbackClass>PWCallback</passwordCallbackClass>        <signaturePropFile>security.properties</signaturePropFile>        <signatureKeyIdentifier                        >SKIKeyIdentifier</signatureKeyIdentifier>        <encryptionKeyIdentifier                       >SKIKeyIdentifier</encryptionKeyIdentifier>        <encryptionUser>frances</encryptionUser>        <signatureParts>           {Element}{http://schemas.xmlsoap.org/soap/envelope/}Body        </signatureParts>        <optimizeParts>            //xenc:EncryptedData/xenc:CipherValue/xenc:CipherData        </optimizeParts>        </action>    </parameter>    <operation name="getNumberOfArticles">        <messageReceiver class=           "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>    </operation></service>
           

InflowSecurity

 是伺服器預期接收的内容(添加了時間戳并随後進行了簽名的消息),而 

OutflowSecurity

 是它将發送回客戶機的内容(添加了時間戳并已進行簽名且資料已加密的消息)。

回頁首

客戶機

在用戶端,Frances 将設定反向過程,如清單 32 中所示。

清單 32. 最終的 axis2.xml 檔案

<axisconfig name="AxisJava2.0">    <!-- Engage the security module -->    <module ref="rampart"/>        <parameter name="OutflowSecurity">      <action>        <items>Timestamp Signature</items>        <user>gene</user>        <passwordCallbackClass>PWCallback</passwordCallbackClass>        <signaturePropFile>security.properties</signaturePropFile>        <signatureKeyIdentifier                        >SKIKeyIdentifier</signatureKeyIdentifier>        <signatureParts>            {Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp</signatureParts>      </action>    </parameter>    <parameter name="InflowSecurity">      <action>        <items>Timestamp Signature Encrypt</items>        <user>gene</user>        <passwordCallbackClass>PWCallback</passwordCallbackClass>        <signaturePropFile>security.properties</signaturePropFile>        <signatureKeyIdentifier                        >SKIKeyIdentifier</signatureKeyIdentifier>        <encryptionKeyIdentifier                       >SKIKeyIdentifier</encryptionKeyIdentifier>        <encryptionUser>frances</encryptionUser>        <signatureParts>           {Element}{http://schemas.xmlsoap.org/soap/envelope/}Body        </signatureParts>        <optimizeParts>           //xenc:EncryptedData/xenc:CipherValue/xenc:CipherData        </optimizeParts>       </action>    </parameter>    <!-- ================================================= -->    <!-- Parameters -->    <!-- ================================================= -->    <parameter name="hotdeployment" locked="false">true</parameter>...
           

現在客戶機将發送添加了時間戳并已簽名的消息,且堅持任何響應都必須帶時間戳,且已簽名和加密。

讓我們看看這對實際消息的影響。

回頁首

請求

清單 33 顯示了最終的請求。

清單 33. 最終的請求

<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv=          "http://schemas.xmlsoap.org/soap/envelope/">   <soapenv:Header>      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">         <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"                                              Id="Signature-5525185">            <ds:SignedInfo>               <ds:CanonicalizationMethod Algorithm=                        "http://www.w3.org/2001/10/xml-exc-c14n#" />               <ds:SignatureMethod Algorithm=                     "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />               <ds:Reference URI="#Timestamp-1741620">                  <ds:Transforms>                     <ds:Transform Algorithm=                        "http://www.w3.org/2001/10/xml-exc-c14n#" />                  </ds:Transforms>                  <ds:DigestMethod Algorithm=                         "http://www.w3.org/2000/09/xmldsig#sha1" />                  <ds:DigestValue>                     TQSR9wUuJ7rJi582TsbNjiAUqZI=                  </ds:DigestValue>               </ds:Reference>            </ds:SignedInfo>             <ds:SignatureValue>aRI5mvvvXZusAB/5cKCx/fOcW+CDjdk1F3IcllObVcEOWws9/mV4X2kWEX3hhwK7koX5jMPpl7AtLSbEh8UQGCa8yBua++yveprFl020ToVtePVOcWsBLM+9VHu9bJbhvaaps43RiUkym6xvVU/yL3eKTbhdhB/RQDI3kylXdas=</ds:SignatureValue>             <ds:KeyInfo Id="KeyId-26644003">                <wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-26174005">                   <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>                </wsse:SecurityTokenReference>             </ds:KeyInfo>          </ds:Signature>          <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"                                           wsu:Id="Timestamp-1741620">             <wsu:Created>2006-06-22T11:34:02.453Z</wsu:Created>             <wsu:Expires>2006-06-22T11:39:02.453Z</wsu:Expires>          </wsu:Timestamp>       </wsse:Security>    </soapenv:Header>    <soapenv:Body>       <cms:getNumberOfArticles                      xmlns:cms="http://daily-moon.com/cms">          <cms:category>classifieds</cms:category>       </cms:getNumberOfArticles>    </soapenv:Body> </soapenv:Envelope>
           

回頁首

響應

清單 34 顯示了最終的響應。

清單 34. 最終的響應

<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv=            "http://schemas.xmlsoap.org/soap/envelope/"             xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">   <soapenv:Header>      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">         <xenc:EncryptedKey Id="EncKeyId-28585008">            <xenc:EncryptionMethod Algorithm=                "http://www.w3.org/2001/04/xmlenc#rsa-1_5" />            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">            <wsse:SecurityTokenReference>               <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">Xeg55vRyK3ZhAEhEf+YT0z986L0=</wsse:KeyIdentifier>            </wsse:SecurityTokenReference>         </ds:KeyInfo>         <xenc:CipherData>            <xenc:CipherValue>NSkylkASezzHSp37izSN3xnxf6v/zwN3C70uU2nUTNk4a9xYxhNcgiVQuS2/Tm3/x3Jm1d9rj2V8x1uqlKmi89MFifN34SDxaDTMBFzhfRv4CmQSITEFjY1ySVDvMb7WZszGDhVIGYkjcDkoK+SfWdxyuaUdNUbPgEihSnFVRXs=</xenc:CipherValue>         </xenc:CipherData>         <xenc:ReferenceList>            <xenc:DataReference URI="#EncDataId-19400027" />         </xenc:ReferenceList>      </xenc:EncryptedKey>      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"                                       Id="Signature-17174249">         <ds:SignedInfo>            <ds:CanonicalizationMethod Algorithm=                     "http://www.w3.org/2001/10/xml-exc-c14n#" />            <ds:SignatureMethod Algorithm=                  "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />               <ds:Reference URI="#id-19400027">                  <ds:Transforms>                     <ds:Transform Algorithm=                    "http://www.w3.org/2001/10/xml-exc-c14n#" />                  </ds:Transforms>                  <ds:DigestMethod Algorithm=                       "http://www.w3.org/2000/09/xmldsig#sha1" />                  <ds:DigestValue>HfdufYEGpvPpfz2+HWKui4npV9s=</ds:DigestValue>               </ds:Reference>               <ds:Reference URI="#SigConf-17122634">                  <ds:Transforms>                     <ds:Transform Algorithm=                        "http://www.w3.org/2001/10/xml-exc-c14n#" />                  </ds:Transforms>                  <ds:DigestMethod Algorithm=                         "http://www.w3.org/2000/09/xmldsig#sha1" />                  <ds:DigestValue>e88WWqudpvW69wN23fgZjQ9ZAio=</ds:DigestValue>               </ds:Reference>            </ds:SignedInfo>            <ds:SignatureValue>aZLon//vwkw2G2Jxcligxod/CgxMjwtlefZihoyUz5FpgSY6RUoI5vuHX2unrWV+EVA2vWdtz/Iyq+RS7j4QtE2XTYovxdyiZPbKXNdFKHyAkpDr0aDLG9rSjyFVcTrUKgAY06t10zi13Daq95nDMH+wAJCYUO0Vor/u0V9Iv7I=</ds:SignatureValue>            <ds:KeyInfo Id="KeyId-22768665">               <wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-18220809">                  <wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>               </wsse:SecurityTokenReference>            </ds:KeyInfo>         </ds:Signature>         <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-6400133">            <wsu:Created>2006-06-22T11:34:04.062Z</wsu:Created>            <wsu:Expires>2006-06-22T11:39:04.062Z</wsu:Expires>         </wsu:Timestamp>         <wsse11:SignatureConfirmation xmlns:wsse11="http://docs.oasis-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-secext-1.1.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" Value="aRI5mvvvXZusAB/5cKCx/fOcW+CDjdk1F3IcllObVcEOWws9/mV4X2kWEX3hhwK7koX5jMPpl7AtLSbEh8UQGCa8yBua++yveprFl020ToVtePVOcWsBLM+9VHu9bJbhvaaps43RiUkym6xvVU/yL3eKTbhdhB/RQDI3kylXdas=" wsu:Id="SigConf-17122634" />      </wsse:Security>   </soapenv:Header>   <soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-19400027">      <xenc:EncryptedData Id="EncDataId-19400027" Type="http://www.w3.org/2001/04/xmlenc#Content">         <xenc:EncryptionMethod Algorithm=              "http://www.w3.org/2001/04/xmlenc#aes128-cbc" />         <xenc:CipherData>               <xenc:CipherValue>f6uWHGsYmGwHuno2j4H7a4qCMhPLTlCIg40pKLciESBzeCT8rvyl+qHXsFkZJq2m4uj9TEFtRX6efQ5MHBEJozMgI03LSVanh6MmHgt5oilIJClWcQifEx0Azeo3KWnQKSc9lg0ywhKJH+JVBsPSP7E19jZAsR77wUEBBIprxs5W597C/mJh38iXSncwWccE7OCckf1x34FCfKHSqn46MCohZWiPZRjSmAI5dGFMKwttzpmsmXrLHLVrsjm4w9onis+Xr5gbi3Gcx6P0F2ZJGLBb9bkGh/IvjYutgzRD7zhyRZxUmM/oZTVsJJ7dA9YOED5l1C64f4yuqR6TtuVw3gIiuspxWafKwlJuuD0/9m6Ri4AvQuOVEioz45MM5FBCQU+0LFceSlEFFKhN9yLUI9hgLsCYRzc8eedPAhZDjJEDHec5M9LZ0C07sKu7Cvnrjiino53xZmk5uQHs4JlNoA==</xenc:CipherValue>         </xenc:CipherData>      </xenc:EncryptedData>   </soapenv:Body></soapenv:Envelope>
           

總結

為了讓 Web 服務真正能在企業環境中使用,需要具有相應的安全功能。通過結合使用 XML Signature 和 XML Encryption 等技術,并提供表示資訊的标準方式,WS-Security 可保護傳入和傳出 SOAP 消息不受多種不同的安全威脅的危害。

通過要求使用數字簽名,可将通路限制為經過授權的個人或組織,并驗證資訊沒有在傳輸過程中被更改。通過包含加密機制,可以防止資料被非目标接收方看到(或至少不能被其了解)。通過添加時間戳(并對其進行簽名),可以防止消息被捕獲和重發。

在本教程中,Daily Moon 的員工對在本系列教程前面部分建立的 Web 服務進行了保護。接下來,在第 5 部分中,我們将了解如何将安全政策應用到服務上。

-- - - -

轉載于:https://my.oschina.net/abcijkxyz/blog/708546