和第三部分同樣,這部分內容其實應該在后面才對,不過當前工作既然做了,也需要寫下來分享,那么就提前插隊到成長記錄當中吧。看了這篇文章以后,可能給人的感覺是有點偏離服務框架的內容。的卻,如果純粹從技術方面來說,這部分應該不屬于服務框架范疇。拿杭州作個例子,杭州是全國唯一一個景點不但不漲價,反而免門票的地方,原因何在,無非是管理者看得遠,景點的門票收益看得到,但是是小頭,免去門票帶來的商機那才是金礦。框架其實也是這樣,如果客戶用起來不方便,甚至都不能用,那么框架再好,也會有人笑話你是個高高在上的理論主意者,這種框架適合于教學,而非實用。現在也是在邁出平臺服務框架兼容性的第一步,那天和同事們開玩笑說,以前聯通移動的wap業務,好在大家的開發語言都相似,isp只需要兼容各種手機客戶端,我們現在要做的就是兼容各種不同開發語言,平臺,以后甚至瀏覽器,我們這種全部都搞通的人出去,那就真的是搶手貨了。
周一測試部和ISV support小組的日報反映,.net的客戶端對于復雜對象數組返回有問題,緊接著就是.net客戶端對于web service的wsse無法調試通過。我以前沒有接觸過.net,沒辦法,硬著個頭皮裝了個vs2005和WSE 3。前面一個問題就是我前面半周間斷性的解決的問題,在第三篇記錄中也寫了。后面的問題比較緊急,也比較嚴重,因為如果wsse不能順利調試通過,那么將會直接影響我們后續將wsse全面部署的計劃,同時ISV已經跟在后面作測試了。看了看時間進度表,下周要進入平臺搜索引擎增強的開發和WSSE性能優化(WSSE對于CPU的消耗真是厲害),因此也就只有兩天,周四和周五。昨天晚上調試到了很晚(我說的很晚可能有些朋友覺得很早,不過對于我這種早睡早起的人來說,真的算晚了),雖然盡力了,但是還是卡在了最后的部分(服務端返回內容的驗證解析),周五一大早到公司就開始繼續調試,一直到了下午5點鐘,我的神哪,讓我看到那個斷點不再跳出一個令我已經看到都反胃的出錯提示框(順便說一下,微軟的vs出錯提示框作的蠻精致,不過再好看都是出錯,2天內看到了不下數百次,再好看也讓人反胃了),最后在群里面大大的發泄了一把,公司一堆人覺得莫名其妙,不知道我受了什么打擊,就搞通一個東西能夠壓抑成這樣,其實這其中的苦也就自己知道,還是那句話:“在沒有調試過.net的程序以前不知道開源的好啊,能看到源碼是多么開心的一件事情啊,整一個在替微軟作白盒測試,連google都被我翻爛了,也就只看到幾個老外在Q,而沒有人在那兒A”。廢話說了那么多,言歸正傳,實踐是建立在理論基礎上的,那么先系統性的來介紹一下關于WSSE的內容(如果概念已經十分熟悉了,跳過即可),以及如何解決.net客戶端無法調試Java發布的web service的問題。
在互連網應用中Web Service已經得到了廣泛的認同,同時也是因為這種廣泛的應用,使得Web Service在規范化方面越來越成熟。企業和企業之間的信息交互,很重要一點就是信息的安全性,電子商務等互連網應用這方面的需求更為突出,如果沒有安全的保證,沒有客戶或者企業愿意將信息在網上交互,同時也不會信任任何接受到的信息。然而,作為SOA的有效技術手段,Web Service的動態性很強,服務的開發者無法預料到服務將在什么環境下被使用,因此服務的安全性變得更加復雜。
在考慮安全性方面主要有三個關鍵性的概念:
機密性(Confidentiality),完整性(Integrity),身份鑒別(Authentication)。
機密性:除了指定的接受者,其他人無法查看消息的內容。通常會使用密鑰(對稱或非對稱)對消息加密,從而保證消息的機密性。
完整性:確保消息在傳輸的過程中沒有被修改。即保證消息的接收者接收到的消息與消息發送者最初發送的消息完全一致。通常會對消息做摘要(Digest),再使用密鑰(對稱,非對稱)加密摘要,從而保證消息的完整性。
身份鑒別:確保消息發送者的身份與消息中所聲稱的用戶身份一致。最簡單的做法就是讓用戶同時發送用戶名和密碼,服務方確認密碼的有效性從而判斷該用戶身份是否與用戶名所代表的一致。然而在實際的應用中的做法通常不會如此簡單,此時往往會使用密鑰對一段信息加密,服務方通過解密此信息確認用戶的身份。
那么如何選擇使用對稱密鑰還是非對稱密鑰?什么時候使用公鑰,什么時候使用私鑰?首先由于對稱密鑰的加密解密速度比非對稱的密鑰快很多(大約1000倍),所以在加密消息的時候一般都使用對稱密鑰。但是有一個問題就是對稱密鑰又如何發布呢?網絡上兩個沒有聯系的用戶如何建立起一個共享的密鑰?這時就需要PKI來幫助我們將這個共享的密鑰建立起來,即利用非對稱密鑰中的公鑰來加密那個共享密鑰,傳遞到私鑰的擁有方。由此可以知道:對稱密鑰加密普通信息,非對稱密鑰加密對稱密鑰。
在Integrity中,使用非對稱密鑰的私鑰加密摘要,得到的東西是一個廣為人知的東西—Digital Signature(數字簽名). 而使用對稱密鑰加密摘要得到的是HMAC(Hash message authentication codes)。他們在保證消息完整性的同時,都具有身份鑒別的功能,不過前者還有一個功能---抗否認性。值得注意的是在Confidentiality中,使用非對稱密鑰方法是用公鑰加密,私鑰解密,而在Integrity中使用非對稱密鑰的方法恰恰相反。
在當前的安全策略上很多時候會使用到SSL和VPN,他們的好處和缺點網上都有評論,但作為和傳輸層無關的安全策略,WS-Security規范無疑是最具廣泛的應用。IBM,BEA,Microsoft共同制定了WS-Security規范,解決了安全的三個基本問題:機密性、完整性、身份鑒別,在Web Services使用SOAP(XML 格式)作為消息封裝協議的背景下,標準化組織分別制定了XML Encryption、XML Digital Signature、與SAML(XML格式的Security Token)三套規范,WS-Security則是規定了如何將以上規范組合起來以滿足Web Services安全需求的一套規范。
XML Signature規范是將數字簽名和XML組合而成的產物,不要以為XML Signature僅僅是將數字簽名技術應用于XML文件。
XML Signature包括以下的功能:
1.XML Signature可以對任何能夠以URI形式(uniform resource identifier)定位的資源做簽名。既包括與簽名同在一個XML文件中的元素,也包括其他XML文件中的元素,甚至可以是非XML形式的資源(比如一個圖形文件),只要能被URI定位到的資源都可以應用XML Signature. 這也代表了XML簽名的對象可以是動態的變化。
2.XML Signature可以對XML文件中的任一元素做簽名,也可以對整個文件做簽名。
3.XML Signature 既可以用非對稱密鑰做簽名(Digital Signature),也可以用對稱密鑰做簽名(HMAC)。
具體的標簽以及含義就不做解釋了,不過如果要做簽名策略配置,需要熟悉這些標簽,這也會影響到后續開發中遇到的各種問題。另外兩個規范這邊就不做說明了,因為現在服務框架暫時只是提供了Signature的要求,如果內容需要加密,那么對于應用來說性能可能是不可接受的,因此需要的是利用SSL和簽名結合的策略來實現完整的安全機制。
對于WSSE的支持
ASF這部分是改造了Tusncay的Web Service子項目,Tuscany子項目內部集成的web service的開源框架是axis2,雖然很多朋友評價xfire好于axis2,不過個人在使用過程中感覺其實兩者各有所長,只是說如何在適當的場合使用,如果需要和Spring很好的集成,那么xfire當然是最好的選擇,如果需要能夠有很好的wsse以及其他開源支持,那么axis2應該是個很不錯的選擇,畢竟apache組織下的開源項目眾多,自家人集成起來更是得心應手,特別是wss4j和axis2的集成,axis2的address和rampart兩個子插件模塊使用起來十分方便,同時在框架的可插入性和模塊化上,覺得axis2要好過xfire。不過axis2的客戶端比xfire要麻煩得多,xfire封裝的好多了,這也是很多人喜歡xfire的緣故了(不過再傻瓜也抵不過.net客戶端的傻瓜,不過這個傻瓜模式無法讓人測試,那么就真的被當成傻瓜了),畢竟易用性往往是吸引到第一批客戶的重要特質,這也是后續做ASF所需要考慮的問題。
使用Axis2的框架結合Jetty這個輕量級內嵌容器作為Web Service發布框架(不得不提的是,在作web service的性能測試的過程中,公司的測試資深人員對于ASF的web service性能作了肯定,其實這和使用Jetty也有一定的關系,現在越來越多的開源框架都使用了Jetty作為內置web輕量級容器,很靈活,同時也可以達到很好的性能要求,在后面工作中對于hessian集成到服務框架中來,也是采用了Hessian+Jetty),并且通過Axis2的rampart集成了wss4j,提供了WSSE的增強功能。
對于認證模式場景需求問題的解決
ASF對于Web Service Security這部分只是要求了Signature,而對于Signature需要提供兩種方式,UserNameToken和X.509證書。前者提供給內部的一些應用使用,后者提供給外部ISV使用,兩者主要差別也就是在性能上,后者經過測試,在CPU的使用上,是6-8倍于不帶Signature的Web Service。
UserNameToken這種模式很簡單,就很類似于我們平常的用戶認證,用戶名和密碼作為明文或者加密,嵌入在Soap Header中即可,客戶端根據本地保存的受信用戶記錄來交驗是否是合法用戶。
X.509就比較特殊一些,所謂的證書,其中包括了公鑰私鑰對(作為簽名和認證使用),證書頒發者的信息(可能是一些CA機構或者是用本地的證書生成工具自己生成),證書擁有者的身份信息,以及一些導入的受信第三方的公鑰證書。當前的證書方式的簽名認證主要有兩種模式,一種是雙方證書都是由第三方CA認證,同時雙方都將對方的CA作為可信的CA,那么請求發起方將會把自己的證書放入到Soap Header中,接受方接受到請求以后,獲取證書,發現是受信的CA,那么就認為請求發起方身份可信,同時在作完整性摘要校對。另一種模式就是雙方的證書可以沒有任何權威的CA作保證,但是雙方首先就需要將附帶自己公鑰的證書發送給對方,對方將這附帶有公鑰的證書分別導入到證書管理庫中(java是某個JKS,.net是windows的當前用戶或者本機的證書管理文件)。雙方交互的時候不需要將證書置入Soap Header中,但是需要將證書的引用標示(序列號或者是X.509 SubjectKeyIdentifier)傳遞給服務端,服務端根據標示在本地的證書庫中查找并且校驗,這種模式的好處就是不需要CA的認證(省錢)同時傳遞的時候不需要將證書帶入到Header中,節省了傳遞報文的大小,缺點就是雙方需要互相保存對方的公鑰證書到本地的證書庫中,同時這種模式也為跨平臺帶來了很多問題,后續的互通中就會提到。
ASF的證書認證模式中采用了后者,因為要求每個ISV去有一個第三方CA作為授權不是很可行,但是問題就是如果ISV需要導入我們的公鑰證書比較方便,但是我們需要管理那么多ISV的證書,同時又需要動態上傳修改保存證書那么就不能用原有的手動導入的模式,同時由于到時候部署的服務器集群不可能都維護一份本地的證書庫,因此需要用數據庫手段來維護,但是在應用啟動以后再要新增或者修改證書,將會比較麻煩,因此采取了擴展wss4j的策略讀取方式來適應新的應用場景。

擴展的CrytoProvider類圖

擴展后的keystore初始化以及signature部分流程圖
這部分設計主要是擴展了WSS4J的CrytoProvider,擴展后的CrytoProvider重載了獲取X509證書的幾個方法,這里類似于AOP,通過提供ICertsLoaderHandler接口來回調獲取其它存儲內的certs構建 visual keystore,同時在作signature的時候,如果發現ISV的cert不存在于當前的visual keystore 中根據CrytoProvider的接口實現,來決定是全部刷新還是部分獲取刷新當前的visual keystore中的certs。這樣就可以達到了動態裝載和刷新certs的要求,同時根據性能要求選擇配置和實現不同的CrytoProvider。
.Net和Java的互通
Java 的客戶端和服務端Security互通很快就搞定了,只是對于一些應用場景做證書管理的擴展。然而,在經歷了.net客戶端調用Java發布的ws返回數組對象類型的問題以后,又一個大難題擺在了我的面前,ISV support小組和測試部的日報上把.net客戶端無法在wsse的模式下調用Java 發布的 Web Service作為了重點問題,需要我支持,那么當然當仁不讓的接下來盡快搞定了,雖然對.net來說,我算是新手中的新手,不過經過兩天的測試,讓我總結出了.net調試的技巧,那就是截包分析(感覺又回到我前幾年在通信行業干活時的狀況,對于對方協議不了解,又沒有源碼可看,那么就截報文來分析么)。開始挺樂觀的,想著WS-Security微軟也是參與者么,應該會嚴格遵守的,估計一天搞定,結果活活的折騰了兩天,下面所描述的如何互通可能總的看起來應該不是很復雜,不過摸索的過程可真是很費事,google的每一條老外的信息都被我看過了,但是Question多Answer少。廢話不多說,進入正題。
首先不管是什么客戶端調用什么服務端,都需要先做一件事情,準備key pairs。在Java中證書管理庫可以通過Jdk提供的key tools這個工具生成jks格式的Java Key Store,可以將公鑰導出,或者將公鑰導入,同時可以生成秘鑰對保存在證書中。在.net中可以通過makecert的工具來生成符合Public Key Cryptography Standards #12,PKCS#12標準定義,包含了公鑰和私鑰的二進制格式的證書形式,以pfx作為證書文件后綴,同時可以通過mmc對windows的證書存儲區進行管理,導入或者導出證書。其實.net和java的互通關鍵問題就是出在證書格式不同以及獲取證書的算法上。下面就具體的描述一下如何從Java的開發者來做好Java WebService和.net互通的工作。
更多內容請參見:
http://blog.csdn.net/cenwenchu79