webdevqa.jp.net

「ServerCertificateValidationCallback」プロパティをデフォルトの動作に戻す方法を教えてください。

単一のメソッド内で次のコード行を使用して、次のホストからのSSL証明書を明示的にチェックして信頼します:MyTrustedCompany.com:

ServicePointManager.ServerCertificateValidationCallback = Function(obj As [Object], certificate As X509Certificate, chain As X509Chain, errors As SslPolicyErrors) (certificate.Subject.Contains("CN=MyTrustedCompany.com"))

コードに問題はありません-> 100%完全に動作します。

問題は、到達範囲が広すぎることです。そのスコープは私がデカールしたメソッド内にのみあると考えましたが、どうやらそれは 'ServicePointManager'オブジェクトのSharedプロパティであり、アプリケーション全体で永続化する必要がありますが、これは望ましくありません。

問題は、後で私のWebサービスなどを呼び出して、「信頼関係を確立できませんでした...」という例外が発生することです。これは、上記のコード行で、そのメソッドに固有のSSL証明書のホスト名を確認するためです。特定の名前(つまり、MyTrustedCompany)と後続のリクエストworkedをチェックする代わりに、すべての証明書が信頼されるように、コールバックから「True」を返すことをすばやくテストしました。これは、このコールバック割り当てがその単一のメソッドよりも親に到達することを私が知っている方法です。確かに、他のすべての証明書名を含めるようにコールバックを拡張できますが、むしろ行うことは、「ServerCertificateValidationCallback」をデフォルトの動作に戻すことです。以下の擬似コードのように:

ServicePointManager.ServerCertificateValidationCallback = Nothing  'Default checking behavior

カスタム検証を削除してデフォルトの動作に戻すにはどうすればよいですか?ありがとう!

16
atconway

これは実際には(単純なように)機能しているように見え、オブジェクトをデフォルトの方法で動作させます。

ServicePointManager.ServerCertificateValidationCallback = Nothing
13
atconway

問題を解決するための重要なポイントは、senderへのRemoteCertificateValidationCallbackパラメータがWebRequestであることです。あなたはあなたのウェブリクエストに対して送信者をチェックすることができるので、あなたはあなたのウェブリクエストをチェックするだけです。これが私の(比較的テストされていない)解決策です:

// Main Code

request = (FtpWebRequest)FtpWebRequest.Create("ftp://example.com");

using(var validator = new WebRequestCertificateValidator(request))
{
    // etc...
}

// WebRequestCertificateValidator Class

public sealed class WebRequestCertificateValidator : IDisposable
{
    private bool disposed;

    private WebRequest request;

    private RemoteCertificateValidationCallback callback;

    /// <summary>
    /// Creates a certificate validator that allows all certificates for the supplied web request.
    /// </summary>
    /// <param name="request">The WebRequest to validate for.</param>
    public WebRequestCertificateValidator(WebRequest request) : this(request, null)
    {
        //
    }

    /// <summary>
    /// Creates a certificate validator that only allows certificates for the supplied web request of the callback returns true.
    /// </summary>
    /// <param name="request">The WebRequest to validate for.</param>
    /// <param name="callback">The delegate that will be called to validate certificates for the WebRequest.</param>
    public WebRequestCertificateValidator(WebRequest request, RemoteCertificateValidationCallback callback)
    {
        this.disposed = false;

        this.request = request;

        this.callback = callback;

        ServicePointManager.ServerCertificateValidationCallback += this.InternalCallback;
    }

    private bool InternalCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        WebRequest request = sender as WebRequest;

        if(request != null)
        {
            if(request == this.request)
            {
                if(this.callback != null)
                {
                    return this.callback(sender, certificate, chain, sslPolicyErrors);
                }
            }
        }

        return true;
    }

    public void Dispose()
    {
        if(!this.disposed)
        {
            ServicePointManager.ServerCertificateValidationCallback -= this.InternalCallback;

            this.callback = null;

            this.request = null;

            this.disposed = true;
        }
    }
}
4
Tom Winter

特定のURLに対してのみtrueを返す必要がある場合がありますが、それ以外の場合は、複数のデリゲートを使用する可能性を残して、必要な処理を行います。各コールバックのロジックには、特定のコンポーネントから呼び出されたときにのみコールバックがtrueを返すようにリフレクションを介したチェックを含めることができるため、特定のURLと特定のアプリケーションの間に一種のトンネルが作成されます。

このコードを使用する1つの方法:1.オブジェクトの寿命の早い段階でmIgnoreBadCertificatesデリゲートを定義します。2. 'beSecure'コードを含むプロパティをtrueに設定します。3. Httpリクエストを送信します。 4.プロパティをfalseに設定します。これは非常に重要であり、呼び出されることを保証する方法で実装する必要があります。 IDisposableパターンは1つのオプションです。

 private System.Net.Security.RemoteCertificateValidationCallback mIgnoreBadCertificates = new
    System.Net.Security.RemoteCertificateValidationCallback(
      delegate { return true; });

if (beSecure)
    {   //require secure communications
        System.Net.ServicePointManager.ServerCertificateValidationCallback -= mIgnoreBadCertificates;
        Iwds.EventLogger.LogVeryFrequentEvent("Requiring Good Certificates from Remote Sites");
    }
    else
    {   /// Allow connections to SSL sites that have unsafe certificates.
        System.Net.ServicePointManager.ServerCertificateValidationCallback += mIgnoreBadCertificates;
        Iwds.EventLogger.LogVeryFrequentEvent("Ignoring Bad Certificates from Remote Sites");
    }
4
Tom
public class OAuthRequestHandler : WebRequestHandler
{
    public OAuthRequestHandler() : base()
    {
        base.ServerCertificateValidationCallback  += this.InternalCallback;
    }

    private bool InternalCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        return certificate.Subject.Contains("CN=MyTrustedCompany.com");
    }
}

そして私のprogram.csコマンドラインテストで:

HttpClient client = new HttpClient(new OAuthRequestHandler());
responseString = await client.GetStringAsync("https://localhost:2345");

証明書と送信者のパラメーターを使用してさらに多くのことを実行できますが、OPは上記を要求しました。

1
OzBob