日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

SOAP 及其安全控制--转载

發(fā)布時(shí)間:2025/4/5 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SOAP 及其安全控制--转载 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:http://my.oschina.net/huangyong/blog/287791

目錄[-]

  • 1. 基于用戶令牌的身份認(rèn)證
  • 2. 基于數(shù)字簽名的身份認(rèn)證
  • 3. SOAP 消息的加密與解密
  • 4. 總結(jié)

通過(guò)上一篇文章,相信您已經(jīng)學(xué)會(huì)了如何使用 CXF 開發(fā)基于 SOAP 的 WS 了。或許您目前對(duì)于底層原理性的東西還不太理解,心中難免會(huì)有些疑問(wèn):

什么是 WSDL?

什么是 SOAP?

如何能讓 SOAP 更加安全?

我將努力通過(guò)本文,針對(duì)以上問(wèn)題,讓您得到一個(gè)滿意的答案。

還等什么呢?就從 WSDL 開始吧!

WSDL 的全稱是 Web Services Description Language(Web 服務(wù)描述語(yǔ)言),用于描述 WS 的具體內(nèi)容。

當(dāng)您成功發(fā)布一個(gè) WS 后,就能在瀏覽器中通過(guò)一個(gè)地址查看基于 WSDL 文檔,它是一個(gè)基于 XML 的文檔。一個(gè)典型的 WSDL 地址如下:

http://localhost:8080/ws/soap/hello?wsdl

注意:WSDL 地址必須帶有一個(gè)?wsdl?參數(shù)。

在瀏覽器中,您會(huì)看到一個(gè)標(biāo)準(zhǔn)的 XML 文檔:

其中,definitions?是 WSDL 的根節(jié)點(diǎn),它包括兩個(gè)重要的屬性:

  • name:WS 名稱,默認(rèn)為“WS 實(shí)現(xiàn)類 + Service”,例如:HelloServiceImplService
  • targetNamespace:WS 目標(biāo)命名空間,默認(rèn)為“WS 實(shí)現(xiàn)類對(duì)應(yīng)包名倒排后構(gòu)成的地址”,例如:http://soap_spring_cxf.ws.demo/
  • 提示:可以在?javax.jws.WebService?注解中配置以上兩個(gè)屬性值,但這個(gè)配置一定要在 WS 實(shí)現(xiàn)類上進(jìn)行,WS 接口類只需標(biāo)注一個(gè) WebService 注解即可。

    在 definitions 這個(gè)根節(jié)點(diǎn)下,有五種類型的子節(jié)點(diǎn),它們分別是:

  • types:描述了 WS 中所涉及的數(shù)據(jù)類型
  • portType:定義了 WS 接口名稱(endpointInterface)及其操作名稱,以及每個(gè)操作的輸入與輸出消息
  • message:對(duì)相關(guān)消息進(jìn)行了定義(供 types 與 portType 使用)
  • binding:提供了對(duì) WS 的數(shù)據(jù)綁定方式
  • service:WS 名稱及其端口名稱(portName),以及對(duì)應(yīng)的 WSDL 地址
  • 其中包括了兩個(gè)重要信息:

  • portName:WS 的端口名稱,默認(rèn)為“WS 實(shí)現(xiàn)類 + Port”,例如:HelloServiceImplPort
  • endpointInterface:WS 的接口名稱,默認(rèn)為“WS 實(shí)現(xiàn)類所實(shí)現(xiàn)的接口”,例如:HelloService
  • 提示:可在?javax.jws.WebService?注解中配置 portName 與 endpointInterface,同樣必須在 WS 實(shí)現(xiàn)類上配置。

    如果說(shuō) WSDL 是用于描述 WS 是什么,那么 SOAP 就用來(lái)表示 WS 里有什么。

    其實(shí) SOAP 就是一個(gè)信封(Envelope),在這個(gè)信封里包括兩個(gè)部分,一是頭(Header),二是體(Body)。用于傳輸?shù)臄?shù)據(jù)都放在 Body 中了,一些特殊的屬性需要放在 Header 中(下面會(huì)看到)。

    一般情況下,將需要傳輸?shù)臄?shù)據(jù)放入 Body 中,而 Header 是沒(méi)有任何內(nèi)容的,看起來(lái)整個(gè) SOAP 消息是這樣的:

    可見,HTTP 請(qǐng)求的 Request Header 與 Request Body,這正好與 SOAP 消息的結(jié)構(gòu)有著異曲同工之妙!

    看到這里,您或許會(huì)有很多疑問(wèn):

  • WS 不應(yīng)該讓任何人都可以調(diào)用的,這樣太不安全了,至少需要做一個(gè)身份認(rèn)證吧?
  • 為了避免第三方惡意程序監(jiān)控 WS 調(diào)用過(guò)程,能否對(duì) SOAP Body 中的數(shù)據(jù)進(jìn)行加密呢?
  • SOAP Header 中究竟可存放什么東西呢?
  • 沒(méi)錯(cuò)!這就是我們今天要展開討論的話題 —— 基于 SOAP 的安全控制。

    在 WS 領(lǐng)域有一個(gè)很強(qiáng)悍的解決方案,名為?WS-Security,它僅僅是一個(gè)規(guī)范,在 Java 業(yè)界里有一個(gè)很權(quán)威的實(shí)現(xiàn),名為?WSS4J。

    下面我將一步步讓您學(xué)會(huì),如何使用?Spring?+?CXF?+?WSS4J?實(shí)現(xiàn)一個(gè)安全可靠的 WS 調(diào)用框架。

    其實(shí)您需要做也就是兩件事情:

  • 認(rèn)證 WS 請(qǐng)求
  • 加密 SOAP 消息
  • 怎樣對(duì) WS 進(jìn)行身份認(rèn)證呢?可使用如下解決方案:

    1. 基于用戶令牌的身份認(rèn)證

    第一步:添加 CXF 提供的 WS-Security 的 Maven 依賴

    <dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-ws-security</artifactId><version>${cxf.version}</version> </dependency>

    其實(shí)底層實(shí)現(xiàn)還是 WSS4J,CXF 只是對(duì)其做了一個(gè)封裝而已。

    第二步:完成服務(wù)端 CXF 相關(guān)配置

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:cxf="http://cxf.apache.org/core"xmlns:jaxws="http://cxf.apache.org/jaxws"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://cxf.apache.org/corehttp://cxf.apache.org/schemas/core.xsdhttp://cxf.apache.org/jaxwshttp://cxf.apache.org/schemas/jaxws.xsd"><bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"><constructor-arg><map><!-- 用戶認(rèn)證(明文密碼) --><entry key="action" value="UsernameToken"/><entry key="passwordType" value="PasswordText"/><entry key="passwordCallbackRef" value-ref="serverPasswordCallback"/></map></constructor-arg></bean><jaxws:endpoint id="helloService" implementor="#helloServiceImpl" address="/soap/hello"><jaxws:inInterceptors><ref bean="wss4jInInterceptor"/></jaxws:inInterceptors></jaxws:endpoint><cxf:bus><cxf:features><cxf:logging/></cxf:features></cxf:bus></beans>

    首先定義了一個(gè)基于 WSS4J 的攔截器(WSS4JInInterceptor),然后通過(guò) 將其配置到 helloService 上,最后使用了 CXF 提供的 Bus 特性,只需要在 Bus 上配置一個(gè) logging feature,就可以監(jiān)控每次 WS 請(qǐng)求與響應(yīng)的日志了。

    注意:這個(gè) WSS4JInInterceptor 是一個(gè) InInterceptor,表示對(duì)輸入的消息進(jìn)行攔截,同樣還有 OutInterceptor,表示對(duì)輸出的消息進(jìn)行攔截。由于以上是服務(wù)器端的配置,因此我們只需要配置 InInterceptor 即可,對(duì)于客戶端而言,我們可以配置 OutInterceptor(下面會(huì)看到)。

    有必要對(duì)以上配置中,關(guān)于 WSS4JInInterceptor 的構(gòu)造器參數(shù)做一個(gè)說(shuō)明。

    • action = UsernameToken:表示使用基于“用戶名令牌”的方式進(jìn)行身份認(rèn)證
    • passwordType = PasswordText:表示密碼以明文方式出現(xiàn)
    • passwordCallbackRef = serverPasswordCallback:需要提供一個(gè)用于密碼驗(yàn)證的回調(diào)處理器(CallbackHandler)

    以下便是 ServerPasswordCallback 的具體實(shí)現(xiàn):

    package demo.ws.soap_spring_cxf_wss4j;import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.wss4j.common.ext.WSPasswordCallback; import org.springframework.stereotype.Component;@Component public class ServerPasswordCallback implements CallbackHandler {private static final Map<String, String> userMap = new HashMap<String, String>();static {userMap.put("client", "clientpass");userMap.put("server", "serverpass");}@Overridepublic void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {WSPasswordCallback callback = (WSPasswordCallback) callbacks[0];String clientUsername = callback.getIdentifier();String serverPassword = userMap.get(clientUsername);if (serverPassword != null) {callback.setPassword(serverPassword);}} }

    可見,它實(shí)現(xiàn)了?javax.security.auth.callback.CallbackHandler?接口,這是 JDK 提供的用于安全認(rèn)證的回調(diào)處理器接口。在代碼中提供了兩個(gè)用戶,分別是 client 與 server,用戶名與密碼存放在 userMap 中。這里需要將 JDK 提供的?javax.security.auth.callback.Callback?轉(zhuǎn)型為 WSS4J 提供的?org.apache.wss4j.common.ext.WSPasswordCallback,在 handle 方法中實(shí)現(xiàn)對(duì)客戶端密碼的驗(yàn)證,最終需要將密碼放入 callback 對(duì)象中。

    第三步:完成客戶端 CXF 相關(guān)配置

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:jaxws="http://cxf.apache.org/jaxws"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsdhttp://cxf.apache.org/jaxwshttp://cxf.apache.org/schemas/jaxws.xsd"><context:component-scan base-package="demo.ws"/><bean id="wss4jOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"><constructor-arg><map><!-- 用戶認(rèn)證(明文密碼) --><entry key="action" value="UsernameToken"/><entry key="user" value="client"/><entry key="passwordType" value="PasswordText"/><entry key="passwordCallbackRef" value-ref="clientPasswordCallback"/></map></constructor-arg></bean><jaxws:client id="helloService"serviceClass="demo.ws.soap_spring_cxf_wss4j.HelloService"address="http://localhost:8080/ws/soap/hello"><jaxws:outInterceptors><ref bean="wss4jOutInterceptor"/></jaxws:outInterceptors></jaxws:client></beans>

    注意:這里使用的是 WSS4JOutInterceptor,它是一個(gè) OutInterceptor,使客戶端對(duì)輸出的消息進(jìn)行攔截。

    WSS4JOutInterceptor 的配置基本上與 WSS4JInInterceptor 大同小異,這里需要提供客戶端的用戶名(user = client),還需要提供一個(gè)客戶端密碼回調(diào)處理器(passwordCallbackRef = clientPasswordCallback),代碼如下:

    package demo.ws.soap_spring_cxf_wss4j;import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; import org.apache.wss4j.common.ext.WSPasswordCallback; import org.springframework.stereotype.Component;@Component public class ClientPasswordCallback implements CallbackHandler {@Overridepublic void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {WSPasswordCallback callback = (WSPasswordCallback) callbacks[0];callback.setPassword("clientpass");} }

    在 ClientPasswordCallback 無(wú)非設(shè)置客戶端用戶的密碼,其它的什么也不用做了。客戶端密碼只能通過(guò)回調(diào)處理器的方式來(lái)提供,而不能在 Spring 中配置。

    第四步:調(diào)用 WS 并觀察控制臺(tái)日志

    部署應(yīng)用并啟動(dòng) Tomcat,再次調(diào)用 WS,此時(shí)會(huì)在 Tomcat 控制臺(tái)里的 Inbound Message 中看到如下 Payload:

    可見,在 SOAP Header 中提供了 UsernameToken 的相關(guān)信息,但 Username 與 Password 都是明文的,SOAP Body 也是明文的,這顯然不是最好的解決方案。

    如果您將 passwordType 由 PasswordText 改為 PasswordDigest(服務(wù)端與客戶端都需要做同樣的修改),那么就會(huì)看到一個(gè)加密過(guò)的密碼:

    除了這種基于用戶名與密碼的身份認(rèn)證以外,還有一種更安全的身份認(rèn)證方式,名為“數(shù)字簽名”。

    2. 基于數(shù)字簽名的身份認(rèn)證

    數(shù)字簽名從字面上理解就是一種基于數(shù)字的簽名方式。也就是說(shuō),當(dāng)客戶端發(fā)送 SOAP 消息時(shí),需要對(duì)其進(jìn)行“簽名”,來(lái)證實(shí)自己的身份,當(dāng)服務(wù)端接收 SOAP 消息時(shí),需要對(duì)其簽名進(jìn)行驗(yàn)證(簡(jiǎn)稱“驗(yàn)簽”)。

    在客戶端與服務(wù)端上都有各自的“密鑰庫(kù)”,這個(gè)密鑰庫(kù)里存放了“密鑰對(duì)”,而密鑰對(duì)實(shí)際上是由“公鑰”與“私鑰”組成的。當(dāng)客戶端發(fā)送 SOAP 消息時(shí),需要使用自己的私鑰進(jìn)行簽名,當(dāng)客戶端接收 SOAP 消息時(shí),需要使用客戶端提供的公鑰進(jìn)行驗(yàn)簽。

    因?yàn)橛姓?qǐng)求就有相應(yīng),所以客戶端與服務(wù)端的消息調(diào)用實(shí)際上是雙向的,也就是說(shuō),客戶端與服務(wù)端的密鑰庫(kù)里所存放的信息是這樣的:

    • 客戶端密鑰庫(kù):客戶端的私鑰(用于簽名)、服務(wù)端的公鑰(用于驗(yàn)簽)
    • 服務(wù)端密鑰庫(kù):服務(wù)端的私鑰(用于簽名)、客戶端的公鑰(用于驗(yàn)簽)

    記住一句話:使用自己的私鑰進(jìn)行簽名,使用對(duì)方的公鑰進(jìn)行驗(yàn)簽。

    可見生成密鑰庫(kù)是我們要做的第一件事情。

    第一步:生成密鑰庫(kù)

    現(xiàn)在您需要?jiǎng)?chuàng)建一個(gè)名為 keystore.bat 的批處理文件,其內(nèi)容如下:

    <!-- lang: shell --> @echo offkeytool -genkeypair -alias server -keyalg RSA -dname "cn=server" -keypass serverpass -keystore server_store.jks -storepass storepass keytool -exportcert -alias server -file server_key.rsa -keystore server_store.jks -storepass storepass keytool -importcert -alias server -file server_key.rsa -keystore client_store.jks -storepass storepass -noprompt del server_key.rsakeytool -genkeypair -alias client -dname "cn=client" -keyalg RSA -keypass clientpass -keystore client_store.jks -storepass storepass keytool -exportcert -alias client -file client_key.rsa -keystore client_store.jks -storepass storepass keytool -importcert -alias client -file client_key.rsa -keystore server_store.jks -storepass storepass -noprompt del client_key.rsa

    在以上這些命令中,使用了 JDK 提供的?keytool?命令行工具,關(guān)于該命令的使用方法,可點(diǎn)擊以下鏈接:

    http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html

    運(yùn)行該批處理程序,將生成兩個(gè)文件:server_store.jks 與 client_store.jks,隨后將 server_store.jks 放入服務(wù)端的 classpath 下,將 client_store.jks 放入客戶端的 classpath 下。如果您在本機(jī)運(yùn)行,那么本機(jī)既是客戶端又是服務(wù)端。

    第二步:完成服務(wù)端 CXF 相關(guān)配置

    ... <bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"><constructor-arg><map><!-- 驗(yàn)簽(使用對(duì)方的公鑰) --><entry key="action" value="Signature"/><entry key="signaturePropFile" value="server.properties"/></map></constructor-arg> </bean> ...

    其中 action 為 Signature,server.properties 內(nèi)容如下:

    org.apache.ws.security.crypto.provider=org.apache.wss4j.common.crypto.Merlin org.apache.ws.security.crypto.merlin.file=server_store.jks org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=storepass

    第三步:完成客戶端 CXF 相關(guān)配置

    ... <bean id="wss4jOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"><constructor-arg><map><!-- 簽名(使用自己的私鑰) --><entry key="action" value="Signature"/><entry key="signaturePropFile" value="client.properties"/><entry key="signatureUser" value="client"/><entry key="passwordCallbackRef" value-ref="clientPasswordCallback"/></map></constructor-arg> </bean> ...

    其中 action 為 Signature,client.properties 內(nèi)容如下:

    org.apache.ws.security.crypto.provider=org.apache.wss4j.common.crypto.Merlin org.apache.ws.security.crypto.merlin.file=client_store.jks org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.password=storepass

    此外,客戶端同樣需要提供簽名用戶(signatureUser)與密碼回調(diào)處理器(passwordCallbackRef)。

    第四步:調(diào)用 WS 并觀察控制臺(tái)日志

    可見,數(shù)字簽名確實(shí)是一種更為安全的身份認(rèn)證方式,但無(wú)法對(duì) SOAP Body 中的數(shù)據(jù)進(jìn)行加密,仍然是“world”。

    究竟怎樣才能加密并解密 SOAP 消息中的數(shù)據(jù)呢?

    3. SOAP 消息的加密與解密

    WSS4J 除了提供簽名與驗(yàn)簽(Signature)這個(gè)特性以外,還提供了加密與解密(Encrypt)功能,您只需要在服務(wù)端與客戶端的配置中稍作修改即可。

    服務(wù)端:

    ... <bean id="wss4jInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"><constructor-arg><map><!-- 驗(yàn)簽 與 解密 --><entry key="action" value="Signature Encrypt"/><!-- 驗(yàn)簽(使用對(duì)方的公鑰) --><entry key="signaturePropFile" value="server.properties"/><!-- 解密(使用自己的私鑰) --><entry key="decryptionPropFile" value="server.properties"/><entry key="passwordCallbackRef" value-ref="serverPasswordCallback"/></map></constructor-arg> </bean> ...

    客戶端:

    ... <bean id="wss4jOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"><constructor-arg><map><!-- 簽名 與 加密 --><entry key="action" value="Signature Encrypt"/><!-- 簽名(使用自己的私鑰) --><entry key="signaturePropFile" value="client.properties"/><entry key="signatureUser" value="client"/><entry key="passwordCallbackRef" value-ref="clientPasswordCallback"/><!-- 加密(使用對(duì)方的公鑰) --><entry key="encryptionPropFile" value="client.properties"/><entry key="encryptionUser" value="server"/></map></constructor-arg> </bean> ...

    可見,客戶端發(fā)送 SOAP 消息時(shí)進(jìn)行簽名(使用自己的私鑰)與加密(使用對(duì)方的公鑰),服務(wù)端接收 SOAP 消息時(shí)進(jìn)行驗(yàn)簽(使用對(duì)方的公鑰)與解密(使用自己的私鑰)。

    現(xiàn)在您看到的 SOAP 消息應(yīng)該是這樣的:

    可見,SOAP 請(qǐng)求不僅簽名了,而且還加密了,這樣的通訊更加安全可靠。

    但是還存在一個(gè)問(wèn)題,雖然 SOAP 請(qǐng)求已經(jīng)很安全了,但 SOAP 響應(yīng)卻沒(méi)有做任何安全控制,看看下面的 SOAP 響應(yīng)吧:

    如何才能對(duì) SOAP 響應(yīng)進(jìn)行簽名與加密呢?相信您一定有辦法做到,不妨親自動(dòng)手試一試吧!

    4. 總結(jié)

    本文的內(nèi)容有些多,確實(shí)需要稍微總結(jié)一下:

  • WSDL 是用于描述 WS 的具體內(nèi)容的
  • SOAP 是用于封裝 WS 請(qǐng)求與響應(yīng)的
  • 可使用“用戶令牌”方式對(duì) WS 進(jìn)行身份認(rèn)證(支持明文密碼與密文密碼)
  • 可使用“數(shù)字簽名”方式對(duì) WS 進(jìn)行身份認(rèn)證
  • 可對(duì) SOAP 消息進(jìn)行加密與解密
  • 關(guān)于“SOAP 安全控制”也就這點(diǎn)事兒了,但關(guān)于“WS 那點(diǎn)事兒”還并沒(méi)有結(jié)束,因?yàn)?RESTful Web Services 在等著您。如何發(fā)布 REST 服務(wù)?如何對(duì) REST 服務(wù)進(jìn)行安全控制?我們下次再見!

    轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/4343027.html

    總結(jié)

    以上是生活随笔為你收集整理的SOAP 及其安全控制--转载的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。