You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置WCF .NET客户端解密双重加密的SOAP响应?

解决方案:解决WCF客户端解密双向认证加密SOAP响应的问题

我之前也碰到过类似的WCF双向证书认证加加密响应的问题,你的异常核心是WCF无法找到解密EncryptedKey所需的证书令牌,咱们一步步拆解解决:

1. 先定位异常根源

你的错误日志明确指出:WCF无法通过响应里的X509IssuerSerialKeyIdentifierClause(对方证书的Issuer和Serial)找到对应的证书,或者你的自定义令牌提供者返回了错误的证书用于解密。

先确认一个关键细节:响应里的两个证书信息有拼写差异,你要格外注意:

  • EncryptedKey中的Issuer:CN=Their Name,O=Their Organisation(完整拼写)
  • Signature中的Issuer:CN=Their Name,O=Their Organisatio(少了最后一个n)
    确保你加载的对方公钥证书(ServiceEncryptingCert)的Issuer和Serial和EncryptedKey里的完全匹配,拼写差一个字符都会导致匹配失败。

2. 修正自定义令牌提供者的逻辑

你的CreateSecurityTokenProvider方法在处理输入消息(接收响应)时,证书返回逻辑有误。解密EncryptedKey需要用客户端自己的私钥证书(对方用你的公钥加密了会话密钥),而验证签名才需要对方的公钥证书。

修改后的代码如下:

Public Overrides Function CreateSecurityTokenProvider(requirement As SecurityTokenRequirement) As SecurityTokenProvider
    Dim result As SecurityTokenProvider
    If requirement.TokenType = System.IdentityModel.Tokens.SecurityTokenTypes.X509Certificate Then
        Dim direction As MessageDirection
        Dim noDirection As Boolean = False
        Try
            direction = requirement.GetProperty(Of MessageDirection)(ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
        Catch ex As Exception
            noDirection = True
        End Try

        ' 处理无方向的令牌请求(通常是客户端自身证书)
        If noDirection Then
            result = New X509SecurityTokenProvider(Me.credentials.ClientEncryptingCert)
        Else
            If direction = MessageDirection.Output Then
                ' 发送请求时:签名用客户端签名证书,加密用对方公钥证书
                If requirement.KeyUsage = IdentityModel.Tokens.SecurityKeyUsage.Signature Then
                    result = New X509SecurityTokenProvider(Me.credentials.ClientSigningCert)
                Else
                    result = New X509SecurityTokenProvider(Me.credentials.ServiceEncryptingCert)
                End If
            Else
                ' 接收响应时:验证签名用对方公钥证书,解密会话密钥用客户端加密证书(带私钥)
                If requirement.KeyUsage = IdentityModel.Tokens.SecurityKeyUsage.SignatureVerification Then
                    result = New X509SecurityTokenProvider(Me.credentials.ServiceEncryptingCert)
                ElseIf requirement.KeyUsage = IdentityModel.Tokens.SecurityKeyUsage.Decryption Then
                    result = New X509SecurityTokenProvider(Me.credentials.ClientEncryptingCert)
                Else
                    result = MyBase.CreateSecurityTokenProvider(requirement)
                End If
            End If
        End If
    Else
        result = MyBase.CreateSecurityTokenProvider(requirement)
    End If
    Return result
End Function

3. 确保证书被正确加入令牌解析器

仅设置ClientCredentials有时不足以让WCF在令牌解析器中找到所有需要的证书,我们可以自定义ClientCredentials的CreateSecurityTokenResolver方法,强制把所有相关证书加入解析器:

Public Class CustomClientCredentials
    Inherits ClientCredentials

    Private ReadOnly _customCreds As YourCredentialClass ' 替换成你的凭证存储类

    Public Sub New(creds As YourCredentialClass)
        MyBase.New()
        _customCreds = creds
    End Sub

    Protected Overrides Function CloneCore() As ClientCredentials
        Return New CustomClientCredentials(_customCreds)
    End Function

    Public Overrides Function CreateSecurityTokenResolver(tokens As SecurityTokenCollection, abortOnFailure As Boolean) As SecurityTokenResolver
        ' 手动添加所有需要的证书到令牌列表
        Dim tokenList As New List(Of SecurityToken) From {
            New X509SecurityToken(_customCreds.ClientEncryptingCert),
            New X509SecurityToken(_customCreds.ClientSigningCert),
            New X509SecurityToken(_customCreds.ServiceEncryptingCert)
        }

        ' 合并默认令牌和自定义令牌
        tokenList.AddRange(tokens)
        Return SecurityTokenResolver.CreateDefaultSecurityTokenResolver(tokenList.AsReadOnly(), abortOnFailure)
    End Function

    ' 把你之前修改后的CreateSecurityTokenProvider方法放在这里
End Class

然后在客户端配置中替换默认的ClientCredentials:

Dim credentials As New CustomClientCredentials(yourCredentialInstance) ' 传入你的凭证实例
client.ChannelFactory.Endpoint.EndpointBehaviors.Remove(GetType(Description.ClientCredentials))
client.ChannelFactory.Endpoint.EndpointBehaviors.Add(credentials)

4. 调整SecurityBindingElement配置

确保你的安全绑定元素配置和对方的SOAP安全规范匹配:

Dim securityBE As SymmetricSecurityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement(
    MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10)
securityBE.MessageProtectionOrder = Security.MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature
securityBE.RequireSignatureConfirmation = True ' 响应包含签名,开启确认
securityBE.SetKeyDerivation(False) ' 如果不需要密钥派生,关闭此选项
securityBE.IncludeTimestamp = True ' 响应包含Timestamp,确保开启此配置

5. 验证证书的私钥可用性

最后确认你的客户端证书(ClientEncryptingCert和ClientSigningCert)确实包含可访问的私钥:

Dim clientEncryptCert = GetCert("e3debd49................e9a6cd39c5")
Console.WriteLine($"加密证书是否有私钥:{clientEncryptCert.HasPrivateKey}")
Console.WriteLine($"私钥是否可访问:{clientEncryptCert.PrivateKey IsNot Nothing}")

Dim clientSignCert = GetCert("40091641................d622761b")
Console.WriteLine($"签名证书是否有私钥:{clientSignCert.HasPrivateKey}")
Console.WriteLine($"私钥是否可访问:{clientSignCert.PrivateKey IsNot Nothing}")

如果私钥不可访问,需要检查证书的存储位置(比如是否在本地机器的Personal存储区)和当前用户的权限。

内容的提问来源于stack exchange,提问作者Ivan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:02:19