程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF安全之EndPointIdentity

WCF安全之EndPointIdentity

編輯:關於.NET

最近在做一個項目,應用了WCF進行分布式開發,中間還涉及到消息路由器等 ,好在有WCF提供了強大的基礎支持,當然,本身也作了不少的擴展,實際,我 最關心的是WCF的安全問題,網上不少朋友介紹的WCF的安全也是少得可憐,微軟 發布的WCF Security GUID好像講得也只是入門級別的教程,離真正應用到項目 中還是有很大的距離,這也讓我萌發了分享的想法,今天先放出來占個位置吧,有反對的朋友磚頭輕 點,呵~,可以告訴你,WCF的安全裡,有很多的小秘密,當然還是要告訴你,並且有此小秘密是要自己去體驗後才知道,在博客排版方面 ,李會軍(軍哥)讓人 感覺最舒服,在解說方面,軍哥也是以簡潔著稱,我在 這裡也學習一下,一起簡潔吧,我希望以後的WCF安全探討裡,一次只講一個小 內容好了~

概述

Windows Communication Foundation (WCF) 是 Microsoft 為構建面向服務的應用程序而提供的統一編程模型(摘自MSDN),在 分布式環境下的安全問題尤為重要,如果你覺得使用了WCF默認的安全措施可以 讓你高枕 無憂,那明天你可就以回家種田了,當然,對於學習來說,足夠了~,但我們講的是真正的項目應用,WCF在各種協議下的安全提供和保證是不盡相同 的。

背景

故事發生在一個陽光明媚的下午,一名女子為了混入某 小區行竊,將上次偷到的管道維修工作牌別在胸前,當她走近管理員身邊時,被 管理員一把抓個正著,原來這小區從上次失竊事件後,已經將維修隊解散,現在 維修都是由管理員聯系外部人員,自然也不用別什麼工作牌了。

問題呈 現

1、許多朋友對這個EndPointIdentity相當的不屑顧,千萬不要小看它 呀,有時候你被wcf弄生弄死的時候還不知道為什麼,這次你應該看清楚了。當 你新建一個WCF服務類庫時,正確的EndPointIdentity聲明如下

<endpoint address ="UserData"  binding="netTcpBinding"  contract="UserService.IUserData"  bindingConfiguration="EndpointBinding">
<identity>
     <dns  value="localhost"/>
</identity>
</endpoint>

說實現,EndPointIdentity這東西在革命 初期(wcf初建立時),我覺得它就像是人一盲腸,多了它也沒啥用,少了它也不 覺得礙事,你不信?刪了試試,你要真刪除了其實也沒什麼。

2、客戶端 如果引用了服務元數據,生成的EndPointIdentity和服務器端的一模一樣,不信 你自己看,實際上,你也可以把它刪除了(革命初期),對服務調用沒啥影響。

3、在你的綁定中,安全選項為None的時候,你想怎麼弄它就怎麼弄它,不要緊,隨便改。如下

<binding  name="EndpointBinding">
   <security  mode="None">
      <transport  clientCredentialType="Windows"  protectionLevel="EncryptAndSign"/>
       <message clientCredentialType="Certificate"/>
    </security>
</binding>

4、一旦你將安 全策略調整為:Transport(傳輸安全)

<security  mode="Transport">
   <transport  clientCredentialType="Windows"  protectionLevel="EncryptAndSign"/>
   <message  clientCredentialType="Certificate"/>
</security>

5、如果你的服務還是像初期一樣沒啥改動 ,僅是啟用了傳輸安全,clientCredentialType的憑據類型也只是windows,沒 有使用證書,那可以肯定,你的服務沒啥問題出現。

6、不過這時候,你 有一天不小心的將EndpointIdentity中的dns元素值誤刪除了1個字 ,我敢肯定,你的惡夢才剛開始,這時候,你再調用服務,將會收到一個異常。

== ==============

未處理 System.ServiceModel.Security.SecurityNegotiationException

Messag e="服務器已拒絕客戶端憑據。"

============ =====

非常限的提示,完全找不到任何線索,可能那時你還以為是 不小心設置了某種安全策略哩或者是證書什麼的沒匹配呢。

正題

IdentityElement類

表示一個配置元素,該配置元素使其他終結 點在與該終結點交換消息時可以對其進行身份驗證。此類不能被繼承。

EndpointIdentity類

一個 abstract 類,實現此類時可提供一個 標識,與終結點交換消息的客戶端可使用該標識對終結點進行身份驗證。

1、這兩兄弟其實是同一人,起到的作用都是一樣,只不過一個是作用於 配置文件,一個作用於托管代碼中。利用EndpointIdentity來向服務器標識自己 是合法的調用,共有6種方式。

(1) 分別是dns、certificate、rsa、 servicePrincipalName(spn)、userPrincipalName(upn)、 certificateReference(x509證書標識),通常情況下,只采用一種,也是最常用 的dns標識方式,當然,我不反對你6種方式一起使用,如何你有需要。

服務建立時默認的標識符為:dns,並且其值為:localhost。

(2)如果你 的服務器dns值為localhost,客戶端的dns與之不匹配,所拋出的異常描述就是 上面的紅色字體內容。

(3)如果服務器dns值已被更改(這個更改當然不是 你改改配置文件中的值就行的),通常情況下,拋出的異常都會告訴你明確的不 匹配,不匹配在哪裡,預期是什麼,實際是什麼,那你改起來就費事了。

2、現在我們再把安全策略調整到消息級別,試試。

//客 戶端配置
<binding name="EndpointBinding">
          <security mode="Message">
             <transport  clientCredentialType="Windows"  protectionLevel="EncryptAndSign"/>
             <message  clientCredentialType="Certificate"/>
           </security>
        </binding>
       </netTcpBinding>
    </bindings>
    <client>
        <endpoint address  ="net.tcp://localhost:8799/UserService/UserData"
                            binding="netTcpBinding"
                            contract="Client.References.IUserData"
                            bindingConfiguration="EndpointBinding"
                            behaviorConfiguration="UserDataBehavior">
           <identity>
            <dns  value="localhost"/>
           </identity>
        </endpoint>
</client>

//服務器配置
<binding  name="EndpointBinding">
           <security mode="Message">
             <transport clientCredentialType="Windows"  protectionLevel="EncryptAndSign"/>
             <message  clientCredentialType="Certificate"/>
           </security>
        </binding>
       </netTcpBinding>
    </bindings>
    <services>
      <service  name="UserService.UserData"  behaviorConfiguration="UserDataBehavior">
         <host>
          <baseAddresses>
            <add baseAddress =  "net.tcp://localhost:8799/UserService" />
           </baseAddresses>
         </host>
        <endpoint address  ="UserData"
                           binding="netTcpBinding"
                            contract="UserService.IUserData"
                            bindingConfiguration="EndpointBinding">
         </endpoint>
</service>

看看配置文 件,你發現了什麼?是的,服務器端的標識被刪除,客戶端的標識還是dns並且 值為localhost,調用服務拋出異常:

=============== ===========

傳出消息標識檢查失敗。所預期的遠程終結點 的 DNS 標識為“localhost”,但是遠程終結點提供的 DNS 請求為 “192168168151service”。如果此遠程終結點合法,您可以通過在 創建通道代理時明確地將 DNS 標識“192168168151service”指定為 EndpointAddress 的“標識”屬性來解決此問題。

==== ======================

在這裡,我們忽略了 一個事實,當你在服務中將安全策略調整了消息級別安全時,服務必須配置x509 證書,正所謂你叫天不應,叫地不靈啊,這時候EndpointIdentity跑出來搞亂了 ,明明服務器默認是dns標識,值為:loclahost。為什麼突然跑出來個 “192168168151service”呀?我也很想知道,原來,在服務配置證 書後,默認的dns將被替換為證書主題,只要你把dns配置改回來,一切又沒問題 了。

新問題

這時候突然冒出來一個新的問題,如果有多個服務器 的時候怎麼辦呀?多個服務器,多半會伴隨著路由器的出現(這只是一種假設,與業務有關),我也很想知道,有多個的時候的情況。

解決它

答 案是通過代碼動態創建一個EndpointIdentity,代碼比較簡單,如下:

UserDataClient client = new UserDataClient();
EndpointIdentity identity = EndpointIdentity.CreateDnsIdentity ("192168168151service");
AddressHeaderCollection  headers = client.Endpoint.Address.Headers;//如果需要,還可以在這裡加 入自定義的頭消息
Uri uri = client.Endpoint.Address.Uri;
EndpointAddress remoteaddress = new EndpointAddress(uri,  identity, headers.ToArray());
UserDataClient newClient = new  UserDataClient(client.Endpoint.Binding, remoteaddress);
newClient.ClientCredentials.ClientCertificate.Certificate =  client.ClientCredentials.ClientCertificate.Certificate;
client.Abort();//關閉舊通道,當然,這裡你還可以用通道工廠創建對象,實際上也很簡單
string msg = newClient.GetData(50);

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved