.netコアで無効なSSL証明書をバイパスする


103

httpsサイトに接続する必要のあるプロジェクトに取り組んでいます。そのサイトの証明書は信頼できないサイトからのものであるため、接続するたびにコードが例外をスローします。.net Core httpで証明書チェックをバイパスする方法はありますか?

以前のバージョンの.NETからこのコードを見ました。私はこのようなものが必要だと思います。

 ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

回答:


28

ServicePointManager.ServerCertificateValidationCallbackは、.NetCoreではサポートされていません。

現在の状況では、これは 次の4.1。* System.Net.Httpコントラクト(HttpClient)の新しいServerCertificateCustomValidationCallbackメソッドになります。.NET Coreチームは、現在4.1契約を締結しています。これについては、ここgithubで読むことができます

プレリリースバージョンのSystem.Net.Http4.1を試すには、ここCoreFxまたはMYGETフィードのソースを直接使用します:https://dotnet.myget.org/gallery/dotnet-core

Githubの現在のWinHttpHandler.ServerCertificateCustomValidationCallback定義


8
これはWindowsでのみ機能します。Linux用のソリューションはありますか?ありがとう。
ウラジミール

145

更新:

以下で説明するように、すべての実装がこのコールバックをサポートしているわけではありません(つまり、iOSなどのプラットフォーム)。この場合、ドキュメントに記載されているように、バリデーターを明示的に設定できます。

handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

これは、.NET Core 2.2、3.0、および3.1でも機能します。

古い答え、より多くの制御がありますが、投げる可能性がありPlatformNotSupportedExceptionます:

このような匿名のコールバック関数を使用して、HTTP呼び出しのSSL証明書チェックをオーバーライドできます。

using (var httpClientHandler = new HttpClientHandler())
{
   httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
   using (var client = new HttpClient(httpClientHandler))
   {
       // Make your request...
   }
}

さらに、ファクトリパターンを使用することをお勧めします。HttpClientこれは、すぐに破棄されない可能性がある共有オブジェクトであり、接続が開いままになるためです。


3
私は.NetCore 1.0を使用していますが、これでうまくいきました。ヘッドアップとして、.Net Core 2.0は、MacOSXでこれを機能させる方法を提供するというHttpClientプロパティを追加DangerousAcceptAnyServerCertificateValidatorしたようです。ここでは詳細情報- github.com/dotnet/corefx/pull/19908
トロイWitthoeft

1
これをAWSLambdaで使用すると、.NET Core 1.0は、カスタムルートCA証明書を使用して内部HTTPSに接続できなかった原因を修正しました。
QuickNull 2017

任意 factory patternのためHttpClient
キケネット2018年

@Kiquenetファクトリを作成するだけで、GetHttpClientメソッドは設定されたものHttpClientを返し、 それを-block内で使用しますusing
LuckyLikey

これは、特に単一のクライアントの使用にスコープできるため、受け入れられる答えである必要があります。
BinaryPatrick

37

私はこれで解決します:

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpClient("HttpClientWithSSLUntrusted").ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            ClientCertificateOptions = ClientCertificateOption.Manual,
            ServerCertificateCustomValidationCallback =
            (httpRequestMessage, cert, cetChain, policyErrors) =>
            {
                return true;
            }
        });

YourService.cs

public UserService(IHttpClientFactory clientFactory, IOptions<AppSettings> appSettings)
    {
        _appSettings = appSettings.Value;
        _clientFactory = clientFactory;
    }

var request = new HttpRequestMessage(...

var client = _clientFactory.CreateClient("HttpClientWithSSLUntrusted");

HttpResponseMessage response = await client.SendAsync(request);

32

同じ問題の答えを探してここに来ましたが、私はNETCore用のWCFを使用しています。同じボートに乗っている場合は、次を使用します。

client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = 
    new X509ServiceCertificateAuthentication()
    {
        CertificateValidationMode = X509CertificateValidationMode.None,
        RevocationMode = X509RevocationMode.NoCheck
    };

すべての証明書とAppDomainに対してグローバルですか?
キケネット2018年

@Kiquenet:そうだと思います、はい。他の場所で更新された回答を確認してください。今より良い解決策があるかもしれません。一年が経ちました。他に何もなければ、オーセンティケーターをサブクラス化できると思います。いいえ、私が知っているHttpClientのネイティブファクトリはありません。より多くの機能が必要な場合は、RestClientをご覧ください。
Troels Larsen 2018

HttpClient(.NET Core 3.1)にはClientCredentialsプロパティはありません。
Павле

@Павле:このプロジェクトはまだ3.1に更新していませんが、次のようなプロパティがあるはずです:docs.microsoft.com/en-us/dotnet/api/…
Troels Larsen

@Павле:この回答は、HttpClientではなく、WCFサービスで生成されたクライアントに関するものです。私のASMXSoapClientでも働いてくれて、どうもありがとう!
ヤンZahradník

14

.NetCoreでは、services configureメソッドで次のコードスニペットを追加できます。開発環境でのみSSL証明書を渡すことだけを確認するためのチェックを追加しました

services.AddHttpClient("HttpClientName", client => {
// code to configure headers etc..
}).ConfigurePrimaryHttpMessageHandler(() => {
                  var handler = new HttpClientHandler();
                  if (hostingEnvironment.IsDevelopment())
                  {
                      handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
                  }
                  return handler;
              });

1
なぜ-veが、これはまさに他の人がmvc.netコードで提案何実装され、彼らはそれにポイントを獲得し、私はちょうど.netCoreコードで同じ実装を示しています
Sameh

多分。説明がまったくないからです。このアプローチが他のアプローチを引き継ぐ必要がある理由、呼び出しセクション(mycontroller.csなど)にどのコードを記述する必要があるか。これは説明の一部である可能性があります。公式の文書/引用。
BhanuChhabra19年

私が言ったように、スレッドの上部にある他のコメントを確認しても、大きな違いはありませんが、18ポイントと81ポイントを獲得しました。
Sameh19年

1
彼らは彼らの答えを裏付けるテキストを追加したので、もう一度ガイドラインを読んでください。あなたを助けるかもしれません、@ moderatorsは私見の正確な問題を指摘することができます。
BhanuChhabra19年

8

.NET Core2.2およびDockerLinuxコンテナーで自己署名証明書とクライアント証明書認証を操作するときに、同じ問題に直面しました。私の開発用Windowsマシンではすべて正常に動作しましたが、Dockerでは次のようなエラーが発生しました。

System.Security.Authentication.AuthenticationException:検証手順に従ってリモート証明書が無効です

幸い、証明書はチェーンを使用して生成されました。もちろん、いつでもこのソリューションを無視して、上記のソリューションを使用できます。

だからここに私の解決策があります:

  1. Chromeを使用してコンピューターに証明書をP7B形式で保存しました。

  2. 次のコマンドを使用して、証明書をPEM形式に変換します。
    openssl pkcs7 -inform DER -outform PEM -in <cert>.p7b -print_certs > ca_bundle.crt

  3. ca_bundle.crtファイルを開き、すべての件名の記録を削除して、クリーンなファイルを残します。以下の例:

    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
  1. これらの行をDockerfileに配置します(最後のステップで):
    # Update system and install curl and ca-certificates
    RUN apt-get update && apt-get install -y curl && apt-get install -y ca-certificates
    # Copy your bundle file to the system trusted storage
    COPY ./ca_bundle.crt /usr/local/share/ca-certificates/ca_bundle.crt
    # During docker build, after this line you will get such output: 1 added, 0 removed; done.
    RUN update-ca-certificates
  1. アプリ内:
    var address = new EndpointAddress("https://serviceUrl");                
    var binding = new BasicHttpsBinding
    {
        CloseTimeout = new TimeSpan(0, 1, 0),
        OpenTimeout = new TimeSpan(0, 1, 0),
        ReceiveTimeout = new TimeSpan(0, 1, 0),
        SendTimeout = new TimeSpan(0, 1, 0),
        MaxBufferPoolSize = 524288,
        MaxBufferSize = 65536,
        MaxReceivedMessageSize = 65536,
        TextEncoding = Encoding.UTF8,
        TransferMode = TransferMode.Buffered,
        UseDefaultWebProxy = true,
        AllowCookies = false,
        BypassProxyOnLocal = false,
        ReaderQuotas = XmlDictionaryReaderQuotas.Max,
        Security =
        {
            Mode = BasicHttpsSecurityMode.Transport,
            Transport = new HttpTransportSecurity
            {
                ClientCredentialType = HttpClientCredentialType.Certificate,
                ProxyCredentialType = HttpProxyCredentialType.None
            }
        }
    };
    var client = new MyWSClient(binding, address);
    client.ClientCredentials.ClientCertificate.Certificate = GetClientCertificate("clientCert.pfx", "passwordForClientCert");
    // Client certs must be installed
    client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication
    {
        CertificateValidationMode = X509CertificateValidationMode.ChainTrust,
        TrustedStoreLocation = StoreLocation.LocalMachine,
        RevocationMode = X509RevocationMode.NoCheck
    };

GetClientCertificateメソッド:

private static X509Certificate2 GetClientCertificate(string clientCertName, string password)
{
    //Create X509Certificate2 object from .pfx file
    byte[] rawData = null;
    using (var f = new FileStream(Path.Combine(AppContext.BaseDirectory, clientCertName), FileMode.Open, FileAccess.Read))
    {
        var size = (int)f.Length;
        var rawData = new byte[size];
        f.Read(rawData, 0, size);
        f.Close();
    }
    return new X509Certificate2(rawData, password);
}

4

まず、本番環境で使用しないでください

AddHttpClientミドルウェアを使用している場合、これは便利です。生産ではなく開発目的で必要だと思います。有効な証明書を作成するまで、このFuncを使用できます。

Func<HttpMessageHandler> configureHandler = () =>
        {
            var bypassCertValidation = Configuration.GetValue<bool>("BypassRemoteCertificateValidation");
            var handler = new HttpClientHandler();
            //!DO NOT DO IT IN PRODUCTION!! GO AND CREATE VALID CERTIFICATE!
            if (bypassCertValidation)
            {
                handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, x509Certificate2, x509Chain, sslPolicyErrors) =>
                {
                    return true;
                };
            }
            return handler;
        };

次のように適用します

services.AddHttpClient<IMyClient, MyClient>(x => { x.BaseAddress = new Uri("https://localhost:5005"); })
        .ConfigurePrimaryHttpMessageHandler(configureHandler);

3

すべての証明書を許可することは非常に強力ですが、危険な場合もあります。有効な証明書と特定の証明書のみを許可する場合は、次のようにすることができます。

using (var httpClientHandler = new HttpClientHandler())
{
    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => {
        if (sslPolicyErrors == SslPolicyErrors.None)
        {
            return true;   //Is valid
        }

        if (cert.GetCertHashString() == "99E92D8447AEF30483B1D7527812C9B7B3A915A7")
        {
            return true;
        }
        return false;
    };
    using (var httpClient = new HttpClient(httpClientHandler))
    {
        var httpResponse = httpClient.GetAsync("https://example.com").Result;
    }
}

元のソース:

https://stackoverflow.com/a/44140506/3850405

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.