匿名消息安全

消息安全匿名示例演示如何实现 Windows Communication Foundation (WCF) 应用程序,该应用程序使用消息级安全性,无需客户端身份验证,但需要使用服务器的 X.509 证书进行服务器身份验证。 客户端和服务器之间的所有应用程序消息都经过签名和加密。 此示例基于 WSHttpBinding 示例。 此示例由 Internet 信息服务(IIS)托管的客户端控制台程序(.exe)和服务库(.dll)组成。 该服务实现定义请求-回复通信模式的协定。

注释

本示例的设置过程和生成说明位于本主题末尾。

此示例向计算器接口添加一个新操作,如果客户端未通过身份验证,则返回 True

public class CalculatorService : ICalculator
{
    public bool IsCallerAnonymous()
    {
        // ServiceSecurityContext.IsAnonymous returns true if the caller is not authenticated.
        return ServiceSecurityContext.Current.IsAnonymous;
    }
    ...
}

该服务公开一个终结点,用于与服务通信,该终结点使用配置文件(Web.config)定义。 终结点由地址、绑定和协定组成。 该绑定已配置为使用 wsHttpBinding 绑定。 wsHttpBinding 绑定的默认安全模式是 Message。 属性 clientCredentialType 设置为 None.

<system.serviceModel>

  <protocolMapping>
    <add scheme="http" binding="wsHttpBinding" />
  </protocolMapping>

  <bindings>
    <wsHttpBinding>
     <!-- This configuration defines the security mode as Message and -->
     <!-- the clientCredentialType as None. This mode provides -->
     <!-- server authentication only using the service certificate. -->

     <binding>
       <security mode="Message">
         <message clientCredentialType="None" />
       </security>
     </binding>
    </wsHttpBinding>
  </bindings>
  ...
</system.serviceModel>

用于服务身份验证的凭据在行为<中>指定。 服务器证书必须包含与SubjectName属性的值相同的值,如以下示例代码中为findValue属性指定的值所示。

<behaviors>
  <serviceBehaviors>
    <behavior>
      <!--
    The serviceCredentials behavior allows you to define a service certificate.
    A service certificate is used by a client to authenticate the service and provide message protection.
    This configuration references the "localhost" certificate installed during the setup instructions.
    -->
      <serviceCredentials>
        <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
      </serviceCredentials>
      <serviceMetadata httpGetEnabled="True"/>
      <serviceDebug includeExceptionDetailInFaults="False" />
    </behavior>
  </serviceBehaviors>
</behaviors>

客户端终结点配置由服务终结点、绑定和协定的绝对地址组成。 wsHttpBinding 绑定的客户端安全模式为 Message。 属性 clientCredentialType 设置为 None.

<system.serviceModel>
  <client>
    <endpoint name=""
             address="http://localhost/servicemodelsamples/service.svc"
             binding="wsHttpBinding"
             behaviorConfiguration="ClientCredentialsBehavior"
             bindingConfiguration="Binding1"
             contract="Microsoft.ServiceModel.Samples.ICalculator" />
  </client>

  <bindings>
    <wsHttpBinding>
      <!--This configuration defines the security mode as -->
      <!--Message and the clientCredentialType as None. -->
      <binding name="Binding1">
        <security mode = "Message">
          <message clientCredentialType="None"/>
        </security>
      </binding>
    </wsHttpBinding>
  </bindings>
  ...
</system.serviceModel>

该示例设置CertificateValidationModePeerOrChainTrust用于对服务的证书进行身份验证。 这项操作在客户端的 App.config 文件的 behaviors 部分中完成。 这意味着,如果证书位于用户的受信任人存储中,则信任该证书而不执行证书颁发者链的验证。 此处使用此设置是为了方便起见,以便无需证书颁发机构(CA)颁发的证书即可运行示例。 此设置的安全性低于默认 ChainTrust。 在生产代码中使用 PeerOrChainTrust 之前,应仔细考虑此设置的安全影响。

客户端实现添加了对 IsCallerAnonymous 方法的调用,其余部分则与 WSHttpBinding 示例无异。

// Create a client with a client endpoint configuration.
CalculatorClient client = new CalculatorClient();

// Call the GetCallerIdentity operation.
Console.WriteLine("IsCallerAnonymous returned: {0}", client.IsCallerAnonymous());

// Call the Add service operation.
double value1 = 100.00D;
double value2 = 15.99D;
double result = client.Add(value1, value2);
Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

...

//Closing the client gracefully closes the connection and cleans up resources.
client.Close();

Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();

运行示例时,操作请求和响应将显示在客户端控制台窗口中。 在客户端窗口中按 Enter 关闭客户端。

IsCallerAnonymous returned: True
Add(100,15.99) = 115.99
Subtract(145,76.54) = 68.46
Multiply(9,81.25) = 731.25
Divide(22,7) = 3.14285714285714
Press <ENTER> to terminate client.

消息安全匿名示例中随附的 Setup.bat 批处理文件允许您配置服务器,以使用相关证书运行需要证书安全性的托管应用程序。 批处理文件可以在两种模式下运行。 若要在单计算机模式下运行批处理文件,请在命令行中键入 setup.bat 。 若要在服务模式下运行它,请键入 setup.bat service。 在跨计算机运行示例时使用此模式。 有关详细信息,请参阅本主题末尾的设置过程。

下面简要概述了批处理文件的不同部分:

  • 创建服务器证书。

    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
    
  • 授予对证书私钥的权限。

    Setup.bat 批处理文件中的以下行可以让 ASP.NET 辅助进程帐户访问 LocalMachine 存储区中存储的服务器证书。

    echo ************
    echo setting privileges on server certificates
    echo ************
    for /F "delims=" %%i in ('"%MSSDK%\bin\FindPrivateKey.exe" My LocalMachine -n CN^=%SERVER_NAME% -a') do set PRIVATE_KEY_FILE=%%i set WP_ACCOUNT=NT AUTHORITY\NETWORK SERVICE
    (ver | findstr "5.1") && set WP_ACCOUNT=%COMPUTERNAME%\ASPNET
    echo Y|cacls.exe "%PRIVATE_KEY_FILE%" /E /G "%WP_ACCOUNT%":R
    iisreset
    

注释

如果你使用的是非美国英语版的 Windows,必须编辑 Setup.bat 文件,并将 NT AUTHORITY\NETWORK SERVICE 帐户名称替换为等效的区域账户名。

设置、生成和运行示例

  1. 确保已为 Windows Communication Foundation 示例 执行One-Time 安装过程。

  2. 若要生成解决方案的 C# 或 Visual Basic .NET 版本,请按照 生成 Windows Communication Foundation 示例中的说明进行操作。

在同一计算机上运行示例

  1. 确保路径包括 Makecert.exe 和 FindPrivateKey.exe 所在的文件夹。

  2. 使用管理员权限打开 Visual Studio 开发人员命令提示窗口,并运行示例安装文件夹中的 Setup.bat。 这会安装运行示例所需的所有证书。

    注释

    安装程序批处理文件旨在从 Visual Studio 的开发人员命令提示符运行。 它要求路径环境变量指向安装 SDK 的目录。 此环境变量在 Visual Studio 开发人员命令提示符内自动设置。

  3. 输入地址 http://localhost/servicemodelsamples/service.svc,使用浏览器验证对服务的访问。

  4. 从 \client\bin 启动 Client.exe。 客户端活动显示在客户端控制台应用程序中。

  5. 如果客户端和服务无法通信,请参阅 WCF 示例 故障排除提示。

跨计算机运行示例

  1. 在服务计算机上创建目录。 使用 Internet Information Services (IIS) 管理工具为此目录创建名为 servicemodelsamples 的虚拟应用程序。

  2. 将服务程序文件从 \inetpub\wwwroot\servicemodelsamples 复制到服务计算机上的虚拟目录。 确保复制 \bin 子目录中的文件。 此外,将 Setup.bat 和 Cleanup.bat 文件复制到服务计算机。

  3. 在客户端计算机上为客户端二进制文件创建目录。

  4. 将客户端程序文件复制到客户端计算机上的客户端目录。 此外,将 Setup.bat、Cleanup.bat和 ImportServiceCert.bat 文件复制到客户端。

  5. 在服务器上,使用管理员权限在 Visual Studio 的开发人员命令提示符下运行 setup.bat service 。 使用 setup.bat 参数运行 service,则使用计算机的完全限定域名创建一个服务证书,并将此服务证书导出到名为 Service.cer 的文件中。

  6. 编辑 Web.config 以反映新的证书名称(在 findValue 的 < 属性中),该名称与计算机的完全限定域名相同。

  7. 将Service.cer文件从服务目录复制到客户端计算机上的客户端目录。

  8. 在客户端计算机上的 Client.exe.config 文件中,更改终结点的地址值以匹配服务的新地址。

  9. 在客户端上,使用管理员权限打开的 Visual Studio 开发人员命令提示符中运行 ImportServiceCert.bat。 这会将服务证书从 Service.cer 文件导入 CurrentUser - TrustedPeople 存储中。

  10. 在客户端计算机上,在命令提示符下启动 Client.exe。 如果客户端和服务无法通信,请参阅 WCF 示例 故障排除提示。

运行示例后进行清理

  • 运行完示例后,在示例文件夹中运行 Cleanup.bat。

注释

在跨计算机运行此示例时,此脚本不会删除客户端上的服务证书。 如果您运行了在不同计算机上使用证书的 Windows Communication Foundation (WCF) 示例,请确保清除已安装在当前用户 - 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.