在服务结构中通过HTTPS调用WCF:请求已中止:无法创建SSL/TLS安全通道

问题描述:

我正在通过HTTPS调用WCF服务。 =>证书没问题。请参阅屏幕截图:enter image description here在服务结构中通过HTTPS调用WCF:请求已中止:无法创建SSL/TLS安全通道

客户端证书安装在我的帐户和本地计算机下。 两者都可用于导出。

因此,我有一段代码在控制台应用程序中工作。当我在网络服务下运行控制台应用程序时,服务调用起作用。

当我将此代码粘贴到StatefullService(服务结构中)时,出现以下异常。

我已验证ServicePointManager.SecurityProtocol这是System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12在控制台应用程序和服务fabcric中。

“System.ServiceModel.Security.SecurityNegotiationException:无法建立SSL/TLS的安全通道”********。cloudapp.azure.com“。---> System.Net .WebException:请求已中止:无法在System.Net.HttpWebRequest.GetResponse()上的System.ServiceModel.Channels.HttpChannelFactory上创建SSL/TLS安全通道。\ r \ n 1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)\r\n --- End of inner exception stack trace ---\r\n\r\nServer stack trace: \r\n at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)\r\n at System.ServiceModel.Channels.HttpChannelFactory 1.HttpRequestChannel.HttpChannelRequest。 System.ServiceModel.Channels.RequestChannel.Request(消息消息,TimeSpan超时)上的WaitForReply(TimeSpan超时)\ r \ n在System.ServiceModel.Dispatcher.RequestChannelBinder.Request(消息消息,TimeSpan超时)\ r \ n \ n在System.ServiceModel.Channels.ServiceChannel.Call(String action,单向布尔值,ProxyOperationRuntime操作,Object [] ins,Object []输出,TimeSpan超时)\ r \ n在System.Se rviceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall,ProxyOperationRuntime操作)\ r \ n在System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage消息)\ r \ n \ r \ n异常rethrown at [0]:\ r \ n在System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke上的System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)\ r \ n(在Message ** & msgData,Int32类型中)\ r \ n在** **************************** \ r \ n在************* ********************在***********************。cs:line 75 \ r \ n在**********************中的********************** * .cs:在*******************的第34行\ r \ n在*************** ********。cs:line 20“

代码如下



      var binding = new BasicHttpBinding(); 
      binding.Security.Mode = BasicHttpSecurityMode.Transport; 
      binding.Security.Transport = new HttpTransportSecurity 
      { 
       ClientCredentialType = HttpClientCredentialType.Certificate, 
      }; 
      string endpoint = "https://********.cloudapp.azure.com/*****/SomeService.svc"; 
      var endpoint1 = new EndpointAddress(endpoint); 

      var factory = new ChannelFactory(binding, endpoint); 

      var clientCredentials = new ClientCredentials(); 
      clientCredentials.ClientCertificate.SetCertificate("CN=my-cn-name", 
       System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, 
       System.Security.Cryptography.X509Certificates.StoreName.My); 

      if (factory.Endpoint.EndpointBehaviors.Contains(typeof(ClientCredentials))) 
      { 
       factory.Endpoint.EndpointBehaviors.Remove(typeof(ClientCredentials)); 
      } 

      factory.Endpoint.EndpointBehaviors.Add(clientCredentials); 

      var channel = factory.CreateChannel(); 

      try 
      { 
       var result = channel.GetData(1); 

       Console.WriteLine("Success"); 
       Console.ReadLine(); 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e); 
       Console.ReadLine(); 
      } 

我想通过服务结构中的HTTPS调用WCF服务? 如果我禁用HTTPS协议并启用现有WCF服务上的HTTP协议,我可以连接。但由于显而易见的原因,我们需要HTTPS。

编辑1

测试:

  1. 与调用的HttpClient和WebRequestHandler服务为GET接受这部作品也是在控制台应用程序的HTML。不在服务结构中。
  2. 从我的个人商店中删除证书。控制台应用程序继续工作,因为它使用本地机器商店(请参阅上面的代码示例)
  3. 通过HTTPS在postman中执行soap请求可以工作。

编辑2

按照这个答案https://serverfault.com/a/132791/135762(网络服务),使工作。

问题是网络服务帐户没有正确的访问权限来访问证书的私钥。

你可以用两种方法解决这个问题。

首先使用powershell和setup.bat来安装和配置证书。

在您的服务结构服务中,在项目的根目录中添加Setup.bat。 编辑服务清单,并添加一个设置入口点

<ExeHost> <Program>Setup.bat</Program> <WorkingFolder>CodePackage</WorkingFolder> </ExeHost>

BAT文件或许应该提升的信任运行。您可以添加以下的应用程序清单 的ServiceManifestImport内部:

<Policies> <RunAsPolicy CodePackageRef="Code" UserRef="SetupAdminUser" EntryPointType="Setup" /> </Policies>

在应用程序清单(在XML的根)的底部添加以下为管理员身份运行。 <Principals> <Users> <User Name="SetupAdminUser"> <MemberOf> <SystemGroup Name="Administrators" /> </MemberOf> </User> </Users> </Principals>

BAT文件很简单: powershell.exe -ExecutionPolicy Bypass -Command ".\Scripts\Install-Certificates.ps1"

PowerShell脚本可以像这样


$pwd = ConvertTo-SecureString -String "YourPassword" -Force -AsPlainText 

function Set-CertificatePermission 
{ 
param 
(
    [Parameter(Position=1, Mandatory=$true)] 
    $cert , 

    [Parameter(Position=2, Mandatory=$true)] 
    [ValidateNotNullOrEmpty()] 
    [string]$serviceAccount 
) 


# Specify the user, the permissions and the permission type 
$permission = "$($serviceAccount)","Read,FullControl","Allow" 
$accessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permission; 

# Location of the machine related keys 
$keyPath = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\"; 
$keyName = $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName; 
$keyFullPath = $keyPath + $keyName; 

try 
{ 
    # Get the current acl of the private key 
    $acl = (Get-Acl $keyFullPath) 

    # Add the new ace to the acl of the private key 
    $acl.AddAccessRule($accessRule); 

    # Write back the new acl 
    Set-Acl -Path $keyFullPath -AclObject $acl; 
} 
catch 
{ 
    throw $_; 
} 
} 

function Install-RootCA($path){ 
    Write-Host "Installing root certificate" 

    Import-PfxCertificate -FilePath $path -CertStoreLocation "Cert:\LocalMachine\Root" -Password $pwd -Exportable 
} 

function Install-Certificate($path){ 
    Write-Host "Installing certificate" 

    $cert = Import-PfxCertificate -FilePath $path -CertStoreLocation "Cert:\LocalMachine\My" -Password $pwd -Exportable 
    Set-CertificatePermission $cert "NT AUTHORITY\NETWORK SERVICE" 
} 



Install-RootCA ".\Certificates\CARoot.pfx" 
Install-Certificate ".\Certificates\ClientCert.pfx" 

这将安装在受信任的根存储中的证书(因为我们使用自签名证书)并在计算机帐户的个人存储中安装证书。 服务结构的重要一点是,它还为网络服务访问专用密钥设置了正确的权限。

方法二:曼纽尔使用MMC

  1. 按下Windows键+ R
  2. 键入mmc
  3. 文件=>添加/删除拍打
  4. 添加证书
  5. 选择计算机帐户
  6. 右键单击受信任的根证书颁发机构\证书
  7. 导入根证书* .PFX(将其标记为可导出)
  8. 右击个人\证书
  9. 导入客户端证书*。PFX(将其标记为可导出),对进口客户证书
  10. 右键点击:所有任务=>管理私钥
  11. 添加网络服务的用户,并赋予它完全控制

有一个3路这比上面那些应该适用于WCF的简单。如果此服务在网络服务帐户下运行,那么您可以将“protocol = https”放入服务端点声明中,这样就可以执行缓存;

<Resources> 
    <Endpoints> 
    <Endpoint Name="ServiceEndpoint" Protocol="https" /> 
</Endpoints> 

您也可以选择返回证书到客户端,也有不同的安全权限下运行此服务。详情请看这里https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-application-runas-security#assign-a-security-access-policy-for-http-and-https-endpoints