3

私は数年前に、サードパーティのSOAPWebサービスを含むいくつかのソースからのデータを処理するWindowsサービスを作成しました。サードパーティから提供されたクライアント証明書を使用して、このWebサービスで認証されました。これは、その時点では正常に機能し、デプロイされた元のマシンでも正常に機能していますが、現在、接続の試行で次のメッセージを含む例外がスローされる新しいマシンに移行しています。

クライアント認証スキーム「匿名」でHTTPリクエストが禁止されました

同じことが私の開発マシンでも起こっています。これは、Webサービスへの接続を構成するコードです。

Friend Shared Function GetProperlyConfiguredConnection() As SEMOService.MIWebServiceClient
    ' Ensure that the settings are valid
    ValidateSettings()

    Dim destAddress As New System.ServiceModel.EndpointAddress(Url)
    ' The service uses SOAP 1.1 which is what BasicHttpBinding uses. WSHttpBinding uses SOAP 1.2.
    'Dim destBinding As New System.ServiceModel.WSHttpBinding
    Dim destBinding As New System.ServiceModel.BasicHttpBinding
    With destBinding
        .CloseTimeout = New TimeSpan(0, 1, 0)
        .OpenTimeout = New TimeSpan(0, 1, 0)
        .ReceiveTimeout = New TimeSpan(0, 10, 0)
        .SendTimeout = New TimeSpan(0, 1, 0)
        .BypassProxyOnLocal = False
        .HostNameComparisonMode = ServiceModel.HostNameComparisonMode.StrongWildcard
        .MaxBufferPoolSize = 524288
        .MaxReceivedMessageSize = 2147483647
        .MessageEncoding = ServiceModel.WSMessageEncoding.Text
        .TextEncoding = System.Text.Encoding.UTF8
        .UseDefaultWebProxy = True
        .AllowCookies = False

        With .ReaderQuotas
            .MaxDepth = 32
            .MaxStringContentLength = 2147483647
            .MaxArrayLength = 50000000
            .MaxBytesPerRead = 4096
            .MaxNameTableCharCount = 16384
        End With

        .Security.Mode = ServiceModel.BasicHttpSecurityMode.Transport
        .Security.Transport.ClientCredentialType = ServiceModel.HttpClientCredentialType.Certificate
    End With

    Dim wcfService As New SEMOService.MIWebServiceClient(destBinding, destAddress)

    ' Load the certificate from the specified file.
    Dim keyData As Byte()
    Dim keyFileInfo As New IO.FileInfo(SEMOServiceSettings.KeyFilePath)
    Dim keyFileReader As New IO.BinaryReader(New IO.FileStream(SEMOServiceSettings.KeyFilePath, IO.FileMode.Open, IO.FileAccess.Read))
    keyData = keyFileReader.ReadBytes(keyFileInfo.Length)
    keyFileReader.Close()

    Dim cert As New X509Certificates.X509Certificate2
    cert = New X509Certificates.X509Certificate2(keyData, SEMOServiceSettings.KeyFilePassword)

    wcfService.ClientCredentials.ClientCertificate.Certificate = cert

    Return wcfService
End Function

これは実際にはWCFWebサービスではありませんが、WSDLからクライアントコードを自動生成するときにVisualStudioは気にしなかったようです。クライアント証明書は、証明書ストアからではなくファイルからロードされます。同じ証明書ファイルがすべてのマシンで使用されており、コードをステップ実行すると正常にロードされているように見えます。

動作するマシンからのリクエストと、WireSharkを使用する開発マシンからのリクエストを比較したところ、クライアント証明書がハンドシェイクに含まれていないようです。

クライアント証明書なし

これは、動作するマシン上のリクエストからの対応するパケットです。

完全な証明書チェーン

WCF、SOAP、暗号化については理解できないことがたくさんあるので、この動作をもたらすために環境について何が異なる可能性があるのか​​、そしてそれを修正するために何を変更する必要があるのか​​について少し迷っています。

この質問は関連しているようですが、コードを介してプロパティにアクセスできないようでRequireClientCertificate、app.configを使用してバインディングを構成していません。

サーバー証明書のカスタム検証を実行するために、ServicePointManagerクラスにコールバックを追加することができます。基本クライアントクラスまたはバインディングは、サーバーに送信する前にクライアント証明書の検証を実行しますか?もしそうなら、サーバー証明書の検証と同じ方法でそのプロセスに介入して、何が起こっているのかを確認する方法はありますか?

4

3 に答える 3

1

私はそれを完全に理解しているかどうかはわかりませんが、解決策を見つけました。問題は、クライアント証明書(またはチェーン内の他の証明書の一部)が、要求を行うユーザーの個人証明書ストアに存在する必要があることでした。Windowsサービスを実行するユーザーとしてログオンし、証明書をストアにインポートしました。これですべてが機能しています。

これは、クライアント証明書がストアで参照されるのではなくファイルからロードされた場合でも、何らかの方法で検証されることを示しています。これは、ProcMonの出力で実際に明らかでした。もっと注意を払っていれば、証明書ストアを検索して、NOTFOUNDの結果が出ていることに気づいたでしょう。

MicrosoftのWCFクライアントコードが、証明書なしで続行しようとするのではなく、証明書に問題がある場合に例外をスローすると便利です。まぁ...

于 2012-11-02T15:45:33.443 に答える
0

このように、新しいサーバーの展開に問題がある可能性があります。これは、「以前は機能していた」という事実のためだけに言えます。構成、具体的にはそれを実行することになっているアプリプールとアプリケーション/ユーザーアカウントを確認してもらいます。何かにアクセスする権限がないシステムまたはローカルサービスの下にサービスをインストールした可能性があります。多くの場合、サービス/ユーザーアカウントを含めるためにすべてをコピーしたが、アカウントを作成したことがない展開を見たことがあります。これによりエラーが発生し、サービスにマシン証明書にアクセスしたりチェーンを実行したりする権限がない場合、クライアントに証明書の送信を要求することはありません。

「HTTPリクエストはクライアント認証スキーム「匿名」で禁止されましたか?」を確認してください。

編集:私が以前にしなかった他の質問に答えるために...クライアントは、メッセージ資格情報モードでメッセージに署名するために証明書を使用することを除いて、送信する前にクライアント証明書のいかなるタイプのチェックも行いません。クライアントはサービスを検証します。サービスの資格情報を使用している場合、特にサービスで証明書を使用している場合(IISを介したSSLでも)、WCFクライアントは、通信を許可する前に、証明書が信頼され、ストアにあることを確認します。 。

カスタムのクライアント側サービスバリデーターを作成する方法は見たことがありませんが、最善の策は、診断トレースとメッセージログクライアント側をオンにして、そこから分析することです。

EDIT2:わかりました、それで私はあなたの質問もあまり読みませんでした。元のサービスはサービスアカウント、おそらくネットワークサービスとして実行されていたと思います(それが最も理にかなっているのでしょうか?)。実は、新しいバージョンのWindowsでは、ボットなど、あなたがやろうとしていることと同じようなことをするセキュリティの問題を防ぐために、組み込みのサービスアカウントの一部が制限されています。その上、セットアップに応じてプロキシを使用していますが、これを機能させるにはWindows認証が必要になる可能性があります。「適切な」方法に従って、そのサービスの特定のサービスユーザーを作成することをお勧めします。サービスを「ローカルシステム」として実行するように設定すると、機能する可能性があります(プロキシについてはわかりませんが)。

于 2012-10-31T13:36:56.270 に答える
0

私は、Windows 7サーバーのトランスポートレベルで証明書認証を必要とするサードパーティのWebサービスを利用する際に、この同じ問題に遭遇しました。カスタムアプリケーションIDで実行されているサービスコンシューマーがクライアント証明書の秘密鍵を読み取るアクセス権を持っていなかった根本原因を見つけるために、ソケットレベルでトレースを設定する必要がありました。証明書が見つかっていることを確認しましたが、秘密鍵を読み取ることができなかったため、AcquireCredentailsHandleはエラー0X8009030Dで失敗しました。

ソケットトレース:

System.Net Information: 0 : [5708] SecureChannel#15271547 - Certificate is of type     X509Certificate2 and contains the private key.
ProcessId=6572
ThreadId=1
DateTime=2013-12-18T03:01:54.0189534Z
Timestamp=38085697406996
System.Net Information: 0 : [5708] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent  = Outbound, scc     = System.Net.SecureCredential)
ProcessId=6572
ThreadId=1
DateTime=2013-12-18T03:01:54.0194535Z
Timestamp=38085697408545
System.Net Error: 0 : [5708] AcquireCredentialsHandle() failed with error 0X8009030D.
ProcessId=6572
ThreadId=1
DateTime=2013-12-18T03:01:54.0724641Z
Timestamp=38085698170444

アプリケーションIDにプライベートキーへのアクセスを許可すると、tlsハンドシェイクを完了することができ、証明書がサービスに送信されました。秘密鍵へのアクセスを許可することは、xpマシンで使用していたWindows7サーバーではるかに簡単です。mmcで証明書ストアを開いてクライアント証明書を見つけ、alltaskを右クリックして->秘密鍵を管理するだけです

于 2013-12-18T14:10:51.370 に答える