消息佇列的訊息安全性
MessageSecurity 範例 示範如何針對用戶端實作使用 WS-Security 搭配 X.509v3 憑證驗證的應用程式,並使用伺服器的 X.509v3 憑證透過 MSMQ 進行伺服器驗證。 訊息安全性有時更需要確保 MSMQ 存放區中的訊息保持加密,而且應用程式可以執行自己的訊息驗證。
此範例是以 Transacted MSMQ 系結 範例為基礎。 訊息會加密並簽署。
要設定、建置和執行範例,請執行以下步驟:
請確定您已針對 Windows Communication Foundation 範例 執行One-Time 安裝程式。
如果服務先執行,它會檢查以確定佇列存在。 如果佇列不存在,服務將會建立一個佇列。 您可以先執行服務來建立佇列,也可以透過 MSMQ 佇列管理員建立佇列。 請遵循下列步驟,在 Windows 2008 中建立佇列。
在 Visual Studio 2012 中開啟伺服器管理員。
展開 [功能] 索引標籤。
以滑鼠右鍵按下 私人消息佇列,然後選取 新增,私人佇列。
勾選 [交易式] 方塊。
輸入
ServiceModelSamplesTransacted
作為新佇列的名稱。
若要建置解決方案的 C# 或 Visual Basic 版本,請遵循 建置 Windows Communication Foundation 範例中的指示。
在同一部電腦上運行範例
請確定路徑包含包含 Makecert.exe 和 FindPrivateKey.exe的資料夾。
從範例安裝資料夾執行 Setup.bat。 這會安裝執行範例所需的所有憑證。
注意
當您完成範例時,請執行 Cleanup.bat,確保您已移除憑證。 其他安全性範例使用相同的憑證。
從 \service\bin 啟動 Service.exe。
從 \client\bin 啟動 Client.exe。 用戶端活動會顯示在用戶端主控台應用程式上。
如果客戶端和服務無法通訊,請參閱 WCF 範例 的疑難解答秘訣。
若要在不同電腦之間執行範例
將 Setup.bat、Cleanup.bat和 ImportClientCert.bat 檔案複製到服務計算機。
在用戶端電腦上為用戶端二進位檔建立目錄。
將用戶端程式檔案複製到用戶端電腦上的客戶端目錄。 同時將 Setup.bat、Cleanup.bat和 ImportServiceCert.bat 檔案複製到用戶端。
在伺服器上,執行
setup.bat service
。 使用service
自變數執行setup.bat
會建立具有電腦完整域名的服務憑證,並將服務憑證導出至名為 Service.cer 的檔案。編輯服務的 service.exe.config,以反映新的憑證名稱(在 <serviceCertificate>的
findValue
屬性中),該名稱與電腦的完整域名相同。將Service.cer檔案從服務目錄複製到用戶端電腦上的客戶端目錄。
在用戶端上,執行
setup.bat client
。 使用client
自變數執行setup.bat
會建立名為 client.com 的用戶端憑證,並將客戶端憑證導出至名為 Client.cer 的檔案。在用戶端電腦上的 Client.exe.config 檔案中,變更端點的位址值,以符合您服務的新位址。 將localhost替換為伺服器的完整網域名稱。 您也必須將服務的憑證名稱變更為與服務計算機的完整域名相同(在
clientCredentials
底下serviceCertificate
元素的defaultCertificate
項目的findValue
屬性中)。將Client.cer檔案從客戶端目錄複製到伺服器上的服務目錄。
在用戶端上,執行
ImportServiceCert.bat
。 這會將服務憑證從 Service.cer 檔案匯入 CurrentUser - TrustedPeople 存放區。在伺服器上執行
ImportClientCert.bat
,這會從 Client.cer 檔案將用戶端憑證匯入 LocalMachine - TrustedPeople 存放區。在服務電腦上,從命令提示字元啟動 Service.exe。
在用戶端電腦上,從命令提示字元啟動 Client.exe。 如果客戶端和服務無法通訊,請參閱 WCF 範例 的疑難解答秘訣。
在範例之後清除
在您完成執行範例之後,請在samples資料夾中執行 Cleanup.bat。
注意
在跨電腦執行此範例時,此腳本不會移除用戶端上的服務憑證。 如果您已執行跨計算機使用憑證的 Windows Communication Foundation (WCF) 範例,請務必清除已在 CurrentUser - TrustedPeople 存放區中安裝的服務憑證。 若要這樣做,請使用下列命令:
certmgr -del -r CurrentUser -s TrustedPeople -c -n <Fully Qualified Server Machine Name>
例如:certmgr -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com
。
要求
此範例需要安裝並執行 MSMQ。
演示
用戶端會使用服務的公鑰加密訊息,並使用自己的憑證簽署訊息。 從佇列讀取訊息的服務會使用信任人員存放區中的憑證來驗證客戶端憑證。 然後它會解密訊息,並將訊息分派至服務作業。
因為 Windows Communication Foundation(WCF)訊息會當作 MSMQ 訊息主體中的負載來傳遞,因此主體會保留在 MSMQ 存放區中加密。 這可防止訊息被未經授權洩漏。 請注意,MSMQ 本身並不知道它所攜帶的訊息是否已加密。
此範例示範如何在訊息層級與 MSMQ 搭配使用相互驗證。 憑證會以非同步方式交換。 這一律是佇列應用程式的情況,因為服務和用戶端不需要同時啟動並執行。
描述
範例客戶端和服務程式代碼與 交易 MSMQ 系結 範例相同,但有一個差異。 作業合約會加上保護層級的批注,這表示訊息必須簽署並加密。
// Define a service contract.
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
[OperationContract(IsOneWay = true, ProtectionLevel=ProtectionLevel.EncryptAndSign)]
void SubmitPurchaseOrder(PurchaseOrder po);
}
為了確保使用必要的令牌來識別服務和客戶端來保護訊息,App.config 包含認證資訊。
用戶端組態會指定要驗證服務的服務憑證。 它會使用其 LocalMachine 存放區作為信任的存放區,以依賴服務的有效性。 它也會指定附加至訊息的用戶端憑證,以進行客戶端的服務驗證。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesMessageSecurity"
binding="netMsmqBinding"
bindingConfiguration="messageSecurityBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor"
behaviorConfiguration="ClientCertificateBehavior" />
</client>
<bindings>
<netMsmqBinding>
<binding name="messageSecurityBinding">
<security mode="Message">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</netMsmqBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ClientCertificateBehavior">
<!--
The clientCredentials behavior allows one to define a certificate to present to a service.
A certificate is used by a client to authenticate itself to the service and provide message integrity.
This configuration references the "client.com" certificate installed during the setup instructions.
-->
<clientCredentials>
<clientCertificate findValue="client.com" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName" />
<serviceCertificate>
<defaultCertificate findValue="localhost" storeLocation="CurrentUser" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
<!--
Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate
is in the user's Trusted People store, then it is trusted without performing a
validation of the certificate's issuer chain. This setting is used here for convenience so that the
sample can be run without having to have certificates issued by a certification authority (CA).
This setting is less secure than the default, ChainTrust. The security implications of this
setting should be carefully considered before using PeerOrChainTrust in production code.
-->
<authentication certificateValidationMode="PeerOrChainTrust" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
請注意,安全性模式設定為 Message,且 ClientCredentialType 設定為 Certificate。
服務組態包含服務行為,指定客戶端驗證服務時所使用的服務認證。 伺服器證書主體名稱是在 <serviceCredentials>的 findValue
屬性中指定。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- Use appSetting to configure MSMQ queue name. -->
<add key="queueName" value=".\private$\ServiceModelSamplesMessageSecurity" />
</appSettings>
<system.serviceModel>
<services>
<service
name="Microsoft.ServiceModel.Samples.OrderProcessorService"
behaviorConfiguration="PurchaseOrderServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/ServiceModelSamples/service"/>
</baseAddresses>
</host>
<!-- Define NetMsmqEndpoint -->
<endpoint address="net.msmq://localhost/private/ServiceModelSamplesMessageSecurity"
binding="netMsmqBinding"
bindingConfiguration="messageSecurityBinding"
contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
<!-- The mex endpoint is exposed at http://localhost:8000/ServiceModelSamples/service/mex. -->
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
<netMsmqBinding>
<binding name="messageSecurityBinding">
<security mode="Message">
<message clientCredentialType="Certificate" />
</security>
</binding>
</netMsmqBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="PurchaseOrderServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<!--
The serviceCredentials behavior allows one to define a service certificate.
A service certificate is used by the service to authenticate itself to its clients and to provide message protection.
This configuration references the "localhost" certificate installed during the setup instructions.
-->
<serviceCredentials>
<serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<clientCertificate>
<certificate findValue="client.com" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName"/>
<!--
Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate
is in the user's Trusted People store, then it is trusted without performing a
validation of the certificate's issuer chain. This setting is used here for convenience so that the
sample can be run without having to have certificates issued by a certification authority (CA).
This setting is less secure than the default, ChainTrust. The security implications of this
setting should be carefully considered before using PeerOrChainTrust in production code.
-->
<authentication certificateValidationMode="PeerOrChainTrust" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
此範例示範如何使用組態控制驗證,以及如何從安全性內容取得呼叫端的身分識別,如下列範例程式代碼所示:
// Service class which implements the service contract.
// Added code to write output to the console window.
public class OrderProcessorService : IOrderProcessor
{
private string GetCallerIdentity()
{
// The client certificate is not mapped to a Windows identity by default.
// ServiceSecurityContext.PrimaryIdentity is populated based on the information
// in the certificate that the client used to authenticate itself to the service.
return ServiceSecurityContext.Current.PrimaryIdentity.Name;
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(PurchaseOrder po)
{
Console.WriteLine("Client's Identity {0} ", GetCallerIdentity());
Orders.Add(po);
Console.WriteLine("Processing {0} ", po);
}
//…
}
執行時,服務程式代碼會顯示客戶端識別。 以下是服務程式代碼的範例輸出:
The service is ready.
Press <ENTER> to terminate service.
Client's Identity CN=client.com; ECA6629A3C695D01832D77EEE836E04891DE9D3C
Processing Purchase Order: 6536e097-da96-4773-9da3-77bab4345b5d
Customer: somecustomer.com
OrderDetails
Order LineItem: 54 of Blue Widget @unit price: $29.99
Order LineItem: 890 of Red Widget @unit price: $45.89
Total cost of this order: $42461.56
Order status: Pending
評論
建立客戶端憑證。
批處理檔中的下一行會建立客戶端憑證。 指定的用戶端名稱會用於所建立憑證的主體名稱。 憑證會儲存在
My
存放區中,位於CurrentUser
存放區位置。echo ************ echo making client cert echo ************ makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%CLIENT_NAME% -sky exchange -pe
將客戶端憑證安裝到伺服器的受信任證書存儲中。
批處理檔中的下一行會將用戶端憑證複製到伺服器的 TrustedPeople 存放區,讓伺服器能夠做出相關的信任或無信任決策。 若要讓安裝在 TrustedPeople 存放區中的憑證受到 Windows Communication Foundation (WCF) 服務的信任,用戶端憑證驗證模式必須設定為
PeerOrChainTrust
或PeerTrust
值。 請參閱先前的服務組態範例,以瞭解如何使用組態檔來完成這項作業。echo ************ echo copying client cert to server's LocalMachine store echo ************ certmgr.exe -add -r CurrentUser -s My -c -n %CLIENT_NAME% -r LocalMachine -s TrustedPeople
建立伺服器證書。
Setup.bat 批次處理檔中的下列幾行會建立要使用的伺服器憑證:
echo ************ echo Server cert setup starting echo %SERVER_NAME% echo ************ echo making server cert echo ************ makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
%SERVER_NAME% 變數會指定伺服器名稱。 憑證會儲存在LocalMachine存放區中。 如果安裝程式批處理檔是以服務參數執行(例如
setup.bat service
),則 %SERVER_NAME% 包含電腦的完整網域名稱。 否則會預設為localhost。將伺服器證書安裝到用戶端的受信任證書存儲中。
下列這一行會將伺服器證書複製到用戶端信任的人員存放區。 這是必要步驟,因為客戶端系統不會隱含信任 Makecert.exe 所產生的憑證。 如果您已經有一個以用戶端信任的根目錄憑證為基礎的憑證,例如 Microsoft 發行的憑證,則不需要進行將伺服器憑證存入客戶端憑證存儲的這一步驟。
certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
注意
如果您使用非美國英文版的 Microsoft Windows,您必須編輯 Setup.bat 檔案,並以您的區域等值名稱取代 “NT AUTHORITY\NETWORK SERVICE” 帳戶名稱。