摘要:【WCF安全】WCF X.509 證書雙向認證
一、SSL運作原理
a. Client端(Browser…)向Server端請求,發送相應Client端支持加密算法列表,Server會根據提供的算法列表選擇最佳的算法。
b. Server端發送最佳算法與證書給Client端。
c. Client端通過第三方CA證書來確認Server端身分。如信任則成功生成一隨機數作為(Session Key),也成為工作階段金鑰。
d.Session Key緩存在Client端,然後Client利用Server端發送的證書中的公鑰(Public Key)加密Session Key放送到Sever端。
e. Server端接收加密後的Session Key 通過自己擁有的私鑰(Private Key)解密而得到Session Key.
f. 雙方通過Session Key對稱加密來傳輸信息。
所以SSL的終極目標就是使用對稱密鑰。
二、WCF 安全模式
WCF綁定,默認是Message安全模式,也就是消息安全,遵守的規範為WS-Security,與SSL運作原理一樣,密鑰交換與協商期間為非對稱加密,
如果雙方擁有對稱密鑰後,後續採用的是對稱加密。但區別在於它是對SOAP進行加密,也就是應用層加密(Message),而非SSL傳輸層加密(Transport)。
三、WCF 具體實現
a. 建立X.509根證書(自簽)
先通過makecert命令生成根節點證書如下:
makecert -n "CN=WCFRootCA"-a sha1 -len 2048 -r-sv WCFRootCA.pvk WCFRootCA.cer .
命令詳解ref:http://msdn.microsoft.com/zh-cn/library/bfsktky3(v=vs.80).aspx
-n 代表輸出的X.509證書的名稱
-a 使用的加密算法
-len 公鑰的長度.(Defult:1024,長度增加加密程度越高,但效率越慢)
-r 自簽標記
-sv 指定pvkfile
根節點證書需要放置在Server端與Client端的Trusted Root Certification Authorities位置中.讓雙方系統信任WCFRootCA發出的證書.
b. 建立服務端證書
makecert -sk WCF -iv WCFRootCA.pvk -n "CN=WCFServer" -a sha1 -len 2048 -ic WCFRootCA.cer
-srlocalmachine -ss my -sky exchange -pe WCFServer.cer
參數詳解:
-sk 密鑰容器位置,該位置包含私鑰,如果容器不存在,則創建一個.
-iv 頒發者私鑰文件
-ic 頒發者證書文件
-sr 證書安裝位置(Default: CurrentUser)
-ss 主題的存儲名稱,輸出的證書存儲在此處.
-sky 主題的密鑰類型,是簽章類型(signature, 2)或交換類型(exchange,1)
-pe 生成的私鑰標記為可導出,這樣可以把私鑰包含在證書中.
Server端外部程序應有訪問此證書私鑰的權限.
Client端安裝此證書,為了安全性考量,不要給客戶端私鑰. 憑證安裝時要包含私鑰,用於解密.
c. 建立客戶端證書
makecert -sk WCF -iv WCFRootCA.pvk -n "CN=WCFClient" -asha1 -len 2048 -ic WCFRootCA.cer
-srlocalmachine -ss my -sky exchange-pe WCFClient.cer
此命令應該在客戶端生成.
Client端安裝此證書,為了安全性考量,客戶端不要洩露私鑰.憑證安裝時要包含私鑰,用於解密.
綜上所述,總而言之. WCFServer證書與WCFClient證書應該注意私鑰管理問題.
d. Server端WCF Config配置內容
<system.serviceModel>
<services>
<service name="SelfHostingTest.HelloWorldService" behaviorConfiguration="beh1">
<endpoint address="" contract="SelfHostingTest.IHelloWorldService" binding="wsHttpBinding" bindingConfiguration="binding1">
<identity>
<!-- 服務端X509證書的Subject Name-->
<dns value="WCFServer"/>
</identity>
</endpoint>
<!--<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />-->
<host>
<baseAddresses>
<add baseAddress="http://server:8003/hello.svc"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<!-- 設置Server端-->
<serviceBehaviors>
<behavior name="beh1">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true"/>
<serviceCredentials>
<clientCertificate>
<!—
1. 這是默認的驗證客戶端證書.似乎有一個缺點,多個客戶端只能用同一個Client端證書.這會喪失認證的意義.如
不通過證書來識別客戶端,Server可以通過用戶名與密碼方式來識別客戶端.
2.CertificateValidationMode設定為PeerOrChainTrust,默認為ChainTrust.默認認證模式要求服務證書的頒發機構鏈必須在客戶端的”受信任根證書頒發機構”,
,雖然我們已經加入到客戶端的(Trusted Root Certification Authorities),但由於是使用CA根證書是Makecert創建,即使導入到相應存儲區但依然會造成無法通過驗證.
3. 對與WCF 成品交付,為了交易安全,一定需要一個真正的第三方CA證書,而不是自己創建的憑證.認證模式要改為ChainTrust
參考: 1. 為何要設定為PeerOrChainTrust. http://www.cnblogs.com/artech/archive/2011/05/29/Authentication_041.html
3. 自簽憑證的安全隱患http://www.wosign.hk/FAQ/selfsigned_SSL_insecure.htm
-->
<!--<certificate findValue="WCFClient" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>-->
<!--<authentication revocationMode="NoCheck" certificateValidationMode="PeerOrChainTrust" />-->
<!-- 2. 以下是通過Validator識別客戶端證書,個人認為可以一個Server端對多個Client端證書-->
<authentication certificateValidationMode="Custom" customCertificateValidatorType="CertificateValidator.MyX509Validator,CertificateValidator" revocationMode="Online"/>
</clientCertificate>
<serviceCertificate findValue="WCFServer" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
<issuedTokenAuthentication allowUntrustedRsaIssuers="true"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="binding1">
<security mode="Message">
<transport clientCredentialType="None"/>
<!--security mode of certificate -->
<message negotiateServiceCredential="true" establishSecurityContext="true" clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
d. Client端配置內容
由於Client端的Config是系統自動生成,但生成的配置文件中沒有生成behaviors 的配置,所以通過代碼控制時最優方案.如下:
DimobjService = New MyService.HelloWorldServiceClient()
'1. Set client Certificate
objService.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, _
StoreName.My, _
X509FindType.FindBySubjectName, _
"WCFClient")
' 不對此證書執行吊銷檢查.
objService.ClientCredentials.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck
' 基於以上同樣的理由,我們必須設定為:PeerOrChainTrust.
objService.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
ServiceModel.Security.X509CertificateValidationMode.PeerOrChainTrust
'2. Set Server Certificate
' if negotiateServiceCredential property set false, we must set Server Certificate
objService.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, _
StoreName.TrustedPeople, _
X509FindType.FindBySubjectName, _
"WCFServer")
Dim Result = objService.SayHello("Magic")
e. 其他
1. 證書的存放位置,要根據系統的運行環境來決定,Server端都放置與LocalMachine中,因為其不依賴與某個登錄的用戶.Client端如果是普通的WinForm(依賴於WINDOWS登錄用戶)可以考慮把客戶端證書放置在CurrentUser中. 客戶端存放的Server的憑證最好放置最好在信任的用戶中(TrustedPeople),
人生到處知何似
應似飛鴻踏雪泥