一、wsHttpBinding.1
1、安全模式 – None.2
1.1.服務端代碼...2
1.2.客戶端代碼...3
1.3.測試...3
2、安全模式 – Transport.4
2.1.客戶端驗證:None.5
2.1.1.獲得和安裝證書...5
2.1.2.為端口配置SSL證書...5
2.1.3.服務端代碼...7
2.1.4.客戶端代碼...7
2.1.5.測試...8
2.2.客戶端驗證:Basic.8
2.2.1.獲得和安裝證書...8
2.2.2.為端口配置SSL證書...8
2.2.3.服務端代碼...8
2.2.4.客戶端代碼...9
2.2.5.測試...9
2.3.客戶端驗證:Ntlm...10
2.3.1.獲得和安裝證書...10
2.3.2.為端口配置SSL證書...10
2.3.3.服務端代碼...10
2.3.4.客戶端代碼...11
2.3.5.測試...11
2.4.客戶端驗證:Windows.12
2.5.客戶端驗證:Certificate.12
2.5.1.獲得和安裝證書...12
2.5.2.為端口配置SSL證書...12
2.5.3.服務端代碼...12
2.5.4.客戶端代碼...13
2.5.5.測試...13
2.6.安全模式 – Transport 存在的問題...14
一、wsHttpBinding
WSHttpBinding是WCF中最常用的一種綁定。缺省的,此綁定實現WS-Security 協議,提供跟實現WS-*協議的服務交換的能力。
共用測試WCF服務類
所有測試都是用同樣的服務端contract和實現這個contract的service:
[ServiceContract(Namespace = "http://chnking.com")]
public interface IGetIdentity
{
[OperationContract]
string Get(string ClientIdentity);
}
public class GetIdentity : IGetIdentity
{
public string Get(string ClientIdentity)
{
return ("服務端Identity 是'" + ServiceSecurityContext.Current.PrimaryIdentity.Name +
"'\n\r客戶端Identity是 '" + ClientIdentity + "'");
}
}
代碼很簡單,一個contract提供了一個Get方法,接收一個string參數,返回 一個string參數。在後面的測試中,客戶端把客戶端安全上下文的Identity發送 到服務端,服務端返回服務端安全上下文的Identity給客戶端。
1、安全模式 – None
這部分的測試代碼:WSHttpBinding_None.rar
WSHttpBinding綁定默認的安全模式是Message,提供消息層的安全性,但是 也提供None安全模式的選擇,None安全模式不提供任何安全性和身份驗證。
這種方式的安全性:
完整性 不提供 保密性 不提供 服務端身份身份驗證 不提供 客戶端身份驗證 無,並忽略客戶端驗證的其他方式設置,固定為None
本例采用全代碼方式,不使用配置文件。
1.1.服務端代碼
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.None;
Uri baseAddress = new Uri ("http://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
1.2.客戶端代碼
static void Main(string[] args)
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.None;
EndpointAddress ea = new EndpointAddress ("http://localhost:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("http://localhost:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
客戶端設置了ClientVia的Vehavior,設置8055為監聽端口,8056為實際端口 ,同時運行TcpTrace來跟蹤通訊數據
1.3.測試
客戶端運行結果:
TCPTrace工具抓客戶端和服務端的通訊數據:
請求消息:
POST /WCFService/GetIdentity HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8
VsDebuggerCausalityData: uIDPoxOaGtpLxrhPjvhVjonkQPMAAAAAjRbg12gZpUemeJRQ0jDM6AKbVL08qshDmMMXS5 qY15kACQAA
Host: localhost:8055
Content-Length: 571
Expect: 100-continue
Connection: Keep-Alive
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap- envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://chnking.com/IGetIdentity/Get& lt;/a:Action>
<a:MessageID>urn:uuid:5071904e-62af-4b1e-b367- 93a48ae2210f</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a: Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost:8056/WCFService/Get Identity</a:To>
</s:Header>
<s:Body>
<Get xmlns="http://chnking.com">
<ClientIdentity>WIN2008\Administrator</ClientIdentity>
</Get>
</s:Body>
</s:Envelope>
響應消息:
HTTP/1.1 100 Continue
HTTP/1.1 200 OK
Content-Length: 468
Content-Type: application/soap+xml; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Mon, 20 Oct 2008 13:50:55 GMT
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap- envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://chnking.com/IGetIdentity/GetR esponse</a:Action>
<a:RelatesTo>urn:uuid:5071904e-62af-4b1e-b367- 93a48ae2210f</a:RelatesTo>
</s:Header>
<s:Body>
<GetResponse xmlns="http://chnking.com">
<GetResult>
Identity of server is''

Identity of client is 'WIN2008\Administrator'
</GetResult>
</GetResponse>
</s:Body>
</s:Envelope>
從TcpTrace的截獲的通訊數據可以看出:
l WSHttpBinding綁定采用Text編碼。
l WSHttpBinding的None安全模式不對消息加密,從截獲的數據可以看到返 回的消息中文本部分是明文。
2、安全模式 – Transport
WSHttpBinding綁定Transport安全模式,由傳輸層HTTPS保證消息的隱秘性和 完整性。服務端必須有一個SSL證書,客戶端必須信任服務端證書。
WSHttpBinding綁定Transport安全可以通過服務宿主在IIS,通過設置IIS的 SSL通道實現。如果是自宿主的WCF服務,同樣通過SSL over http實現傳輸層的 數據加密,這時需要使用HttpCfg.exe工具把證書綁定到一個特定的端口,端口 號就是endpoint地址中指定的端口號。使用Transport安全模式時,endpoint地 址中必須指定HTTPS協議。
下面例子中都使用自宿主的方式。
2.1.客戶端驗證:None
這部分的測試代碼:WSHttpBinding_Transport_None.rar
這種方式的安全性:
完整性 服務端證書通過SSL保證 保密性 服務端證書通過SSL保證 服務端身份身份驗證 服務端證書通過SSL驗證服務端 客戶端身份驗證 無
2.1.1.獲得和安裝證書
這裡用Makecert.exe工具生成證書,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe - r
這是服務端證書,win2008是服務端的機器名。
如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。
2.1.2.為端口配置SSL證書
當使用WSHttpBinding綁定的Transport安全模式,服務又是自宿主的時候, 必須為端口配置SSL證書。
l 查看已綁定證書的端口
使用如下命令查看已經綁定了SSL證書的端口,一面下面步驟使用重復的端口
httpcfg query ssl
vista或者windows 2008,請用這個命令:
netsh http show sslcert
l 獲得證書的Thumbprint
在證書管理器中查看上一步生成的名字win2008的證書,已獲得這個證書的 Thumbprint:
l 執行HttpCfg.exe命令將證書綁定到端口
使用HttpCfg.exe命令的set模式,執行如下的命令:
httpcfg set ssl -i 0.0.0.0:8056 –h bc2935a1d7aab31911613abcb05e9291fcc7bd60
如果操作系統是vista或者windows 2008,請用這個命令:
netsh http add sslcert ipport=0.0.0.0:8056 certhash=bc2935a1d7aab31911613abcb05e9291fcc7bd60 appid= {0D997C3D- 0599-45FC-90FE-B0373FBF1709}
其中appid為任意的唯一的GUID。
綁定證書到端口時,如果還需要驗證客戶端的證書,執行如下命令:
httpcfg set ssl -i 0.0.0.0:8056 –h bc2935a1d7aab31911613abcb05e9291fcc7bd60 -f 2
如果操作系統是vista或者windows 2008,請用這個命令:
netsh http add sslcert ipport=0.0.0.0:8056 certhash=bc2935a1d7aab31911613abcb05e9291fcc7bd60 appid= {0D997C3D- 0599-45FC-90FE-B0373FBF1709} clientcertnegotiation=enable
刪除證書綁定:
httpcfg delete ssl -i 0.0.0.0:8005 -h 0000000000003ed9cd0c315bbb6dc1c08da5e6
vista或者windows 2008,請用這個命令:
Netsh http delete sslcert ipport=0.0.0.0:8056
2.1.3.服務端代碼
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
Uri baseAddress = new Uri ("Https://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
2.1.4.客戶端代碼
static void Main(string[] args)
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
EndpointAddress ea = new EndpointAddress ("https://win2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("https://win2008:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
2.1.5.測試
客戶端運行結果:
這種場景時,需要特別注意的是,客戶端需要將服務端證書保存到當前用戶 存儲位置的受信任的根證書頒發者存儲區內。否則出現此異常,即使在客戶端包 含不驗證服務端證書的代碼也是一樣。
2.2.客戶端驗證:Basic
這部分的測試代碼:WSHttpBinding_Transport_Basic.rar
這種方式的安全性:
完整性 服務端證書通過SSL保證 保密性 服務端證書通過SSL保證 服務端身份身份驗證 服務端證書通過SSL驗證服務端 客戶端身份驗證 客戶端提供的用戶名和密碼
2.2.1.獲得和安裝證書
這裡用Makecert.exe工具生成證書,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe - r
這是服務端證書,win2008是服務端的機器名。
如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。
2.2.2.為端口配置SSL證書
參考前面“2.1.2.為端口配置SSL證書”
2.2.3.服務端代碼
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
Uri baseAddress = new Uri ("Https://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
2.2.4.客戶端代碼
static void Main(string[] args)
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
EndpointAddress ea = new EndpointAddress ("https://win2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//提供UserName客戶端用戶憑據
gc.ClientCredentials.UserName.UserName = "chnking";
gc.ClientCredentials.UserName.Password = "jjz666";
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("https://win2008:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
2.2.5.測試
客戶端運行結果:
這種場景時,需要特別注意的是,客戶端需要將服務端證書保存到當前用戶 存儲位置的受信任的根證書頒發者存儲區內。否則出現此異常,即使在客戶端包 含不驗證服務端證書的代碼也是一樣。
2.3.客戶端驗證:Ntlm
這部分的測試代碼:WSHttpBinding_Transport_Ntlm.rar
這部分測試WSHttpBinding設置為Transport安全模式,同時客戶端驗證設置 為Ntlm驗證時的情況。
Ntlm身份驗證,是由客戶端提供當前登錄windows用戶的用戶憑據(用戶名和 密碼)發送到服務端進行驗證的方式,當然這裡密碼的傳送有個質詢和加密的過 程,過程中不傳送密碼本身。這個驗證過程不走SSL通道也是安全的。
服務端收到客戶端發送的用戶名和密碼後,如果客戶端發送來的是域用戶則 服務端驗證客戶端域用戶的身份,如果客戶端發送來的是一般windows用戶,則 服務端驗證服務器本身的用戶。
這種方式,如果是一般windows用戶驗證,一定要保證登錄客戶端的用戶和密 碼跟服務端的用戶和密碼都要一致。
這種方式的安全性:
完整性 服務端證書通過SSL保證 保密性 服務端證書通過SSL保證 服務端身份身份驗證 服務端證書通過SSL驗證服務端 客戶端身份驗證 客戶端提供當前登錄windows用戶的用戶憑據(用戶名和密碼 ),服務端驗證。客戶端傳送到服務端的用戶名和密碼同樣被SSL加密。
2.3.1.獲得和安裝證書
這裡用Makecert.exe工具生成證書,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe - r
這是服務端證書,win2008是服務端的機器名。
如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。
2.3.2.為端口配置SSL證書
參考前面“2.1.2.為端口配置SSL證書”
2.3.3.服務端代碼
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
Uri baseAddress = new Uri ("Https://localhost:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://localhost:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
2.3.4.客戶端代碼
static void Main(string[] args)
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
EndpointAddress ea = new EndpointAddress ("https://win2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("https://win2008:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
2.3.5.測試
客戶端運行結果:
這種場景時,需要特別注意的是,客戶端需要將服務端證書保存到當前用戶 存儲位置的受信任的根證書頒發者存儲區內。否則出現此異常,即使在客戶端包 含不驗證服務端證書的代碼也是一樣。
2.4.客戶端驗證:Windows
這種驗證方式跟Ntlm方式基本相同,都是驗證客戶端的windows用戶憑據,是 一般windows用戶驗證服務端本地windows用戶,是域用戶的驗證域用戶。有點不 同的是,Windows驗證跟客戶端有個協商過程,如果客戶端機器和服務端機器都 在域,並且客戶端也是以域用戶登錄,則客戶端會使用kerberos驗證方式,傳送 客戶端用戶的kerberos憑據到服務端進行驗證,否則客戶端跟服務端之間使用使 用Ntlm驗證。
跟Ntlm模式比較,在其他配置和代碼方面是一樣的。
2.5.客戶端驗證:Certificate
這部分的測試代碼:WSHttpBinding_Transport_Certificate.rar
這部分測試WSHttpBinding設置為Transport安全模式,同時客戶端驗證設置 為Certificate驗證時的情況。
這種方式的安全性:
完整性 服務端證書通過SSL保證 保密性 服務端證書通過SSL保證 服務端身份身份驗證 服務端證書通過SSL驗證服務端 客戶端身份驗證 客戶端證書
2.5.1.獲得和安裝證書
這裡用Makecert.exe工具生成證書,使用下面的命令:
makecert -sr localmachine -ss My -n CN=win2008 -sky exchange -pe - r
這是服務端證書,win2008是服務端的機器名。
如果做過前面BasicHttpBinding的測試,這個服務端證書就應該已經有了。
makecert -sr currentuser -ss My -n CN=TestClient -sky exchange -pe -r
這是客戶端證書。
2.5.2.為端口配置SSL證書
參考前面“2.1.2.為端口配置SSL證書”
2.5.3.服務端代碼
internal static ServiceHost myServiceHost = null;
internal static void Main()
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
Uri baseAddress = new Uri ("Https://win2008:8056/WCFService/");
myServiceHost = new ServiceHost(typeof(GetIdentity), baseAddress);
ServiceEndpoint myServiceEndpoint = myServiceHost.AddServiceEndpoint
(typeof(IGetIdentity), myBinding, "GetIdentity");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior ();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri ("http://win2008:8057/mex");
myServiceHost.Description.Behaviors.Add(behavior);
myServiceHost.Open();
Console.WriteLine("Service started!");
Console.ReadLine();
myServiceHost.Close();
}
}
2.5.4.客戶端代碼
static void Main(string[] args)
{
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Transport;
myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
EndpointAddress ea = new EndpointAddress ("https://win2008:8056/WCFService/GetIdentity");
GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
//設置客戶端證書
gc.ClientCredentials.ClientCertificate.SetCertificate ("CN=TestClient",
StoreLocation.CurrentUser, StoreName.My);
//為使用TcpTrace跟蹤消息設置的TcpTrace監聽端口
ClientViaBehavior myClientViaBehavior = new ClientViaBehavior
(new Uri ("https://win2008:8055/WCFService/GetIdentity"));
gc.Endpoint.Behaviors.Add(myClientViaBehavior);
//執行代理類Get方法
string result = gc.Get(WindowsIdentity.GetCurrent().Name);
Console.WriteLine(result);
Console.ReadLine();
}
2.5.5.測試
客戶端運行結果:
這種場景時,需要特別注意的是,客戶端需要將服務端證書保存到當前用戶 存儲位置的受信任的根證書頒發者存儲區內。否則出現異常,即使在客戶端包含 不驗證服務端證書的代碼也是一樣。
同樣,在服務端需要把客戶端的證書放到本地機器存儲位置下的受信任根證 書頒發者存儲區內。否則出現異常,即使在服務端包含不驗證客戶端證書的代碼 也是一樣。
2.6.安全模式 – Transport 存在的問題
這部分測試了wsHttpBinding的Transport安全模式的各種客戶端驗證方式的 情況,服務端都是采用的自宿主的方式,服務端證書通過httpcfg或netsh綁定證 書到SSL端口,以實現SSL的傳輸安全。
這部分的測試如文章中的測試結果,全部是成功的,但是所有的這部分的實 例都有個嚴重的問題:
測試的機器在重啟動之前一切測試都正常,可是一旦機器重新啟動後,再次 運行測試服務端和客戶端,在客戶端會出現如下異常:
這個異常就跟服務端證書沒有綁定到SSL端口時是一樣的錯誤。
這時用“netsh http show sslcert”命令查看證書綁定SSL端口 的情況,如下圖,顯示綁定情況正常:
用netsh 命令刪除此SSL端口的綁定,然後再用netsh命令重新綁定證書到SSL 到端口,測試又正常了。重啟後,又會出現上面那個錯誤。
這個問題在網上找了好久,沒找到有人遇到同樣情況的,一直未解決此問題 。希望有遇到同樣問題並解決了的朋友能告知一下。