web-dev-qa-db-ja.com

HttpClientで信頼できないSSL証明書を許可する

SSLを介してWindows 8アプリケーションをテストWeb APIと通信させるのに苦労しています。

HttpClient/HttpClientHandlerは提供せず、WebRequestのような信頼できない証明書を無視するオプションを使用できるようです(ServerCertificateValidationCallbackを使用した「ハッキング」方法でも)。

どんな助けでも大歓迎です!

88
Jamie

Windows 8.1では、無効なSSL証明書を信頼できるようになりました。 Windows.Web.HttpClientを使用するか、System.Net.Http.HttpClientを使用する場合は、私が書いたメッセージハンドラーアダプターを使用できます。 http://www.nuget.org/ packages/WinRtHttpClientHandler

ドキュメントはGitHubにあります: https://github.com/onovotny/WinRtHttpClientHandler

10
Oren Novotny

迅速で汚い解決策は ServicePointManager.ServerCertificateValidationCallback デリゲートを使用することです。これにより、独自の証明書検証を提供できます。検証は、アプリドメイン全体にグローバルに適用されます。

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

これは主に、プロセス中にホストしているエンドポイントに対して実行したい状況で単体テストを行い、 WCFクライアント または HttpClient でヒットしようとしています。 。

量産コードの場合は、よりきめ細かな制御が必要な場合があり、 WebRequestHandler とその ServerCertificateValidationCallback デリゲートプロパティを使用することをお勧めします(下記の dtbの回答 ) 。またはctacke answer を使用して HttpClientHandler を使用します。統合テストでも、他のフックが見つからない場合を除き、以前の方法よりもこれら2つのいずれかを好んでいます。

130
Bronumski

WebRequestHandler Class とその ServerCertificateValidationCallback Property をご覧ください。

using (var handler = new WebRequestHandler())
{
    handler.ServerCertificateValidationCallback = ...

    using (var client = new HttpClient(handler))
    {
        ...
    }
}
76
dtb

.NET標準ライブラリでこれを行おうとしている場合、ハンドラーでtrueを返すだけのすべてのリスクを伴う単純なソリューションがあります。私はあなたに安全を任せます。

var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ServerCertificateCustomValidationCallback = 
    (httpRequestMessage, cert, cetChain, policyErrors) =>
{
    return true;
};

var client = new HttpClient(handler);
28
ctacke

または、Windows.Web.Http名前空間のHttpClientに使用できます。

var filter = new HttpBaseProtocolFilter();
#if DEBUG
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
    filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
#endif
using (var httpClient = new HttpClient(filter)) {
    ...
}
23
dschüsä

ここでのほとんどの回答は、典型的なパターンを使用することを示唆しています。

using (var httpClient = new HttpClient())
{
 // do something
}

iDisposableインターフェースのため。 しないでください!

マイクロソフトは次の理由を説明します。

そしてここでは、舞台裏で起こっている詳細な分析を見つけることができます: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

SSLの質問について https://docs.Microsoft.com/en-us/Azure/architecture/antipatterns/improper-instantiation/#how-to-fix-the-problem に基づいて

パターンは次のとおりです:

class HttpInterface
{
 // https://docs.Microsoft.com/en-us/Azure/architecture/antipatterns/improper-instantiation/#how-to-fix-the-problem
 // https://docs.Microsoft.com/en-us/dotnet/api/system.net.http.httpclient#remarks
 private static readonly HttpClient client;

 // static initialize
 static HttpInterface()
 {
  // choose one of these depending on your framework

  // HttpClientHandler is an HttpMessageHandler with a common set of properties
  var handler = new HttpClientHandler();
  {
      ServerCertificateCustomValidationCallback = delegate { return true; },
  };
  // derives from HttpClientHandler but adds properties that generally only are available on full .NET
  var handler = new WebRequestHandler()
  {
      ServerCertificateValidationCallback = delegate { return true; },
      ServerCertificateCustomValidationCallback = delegate { return true; },
  };

  client = new HttpClient(handler);
 }

 .....

 // in your code use the static client to do your stuff
 var jsonEncoded = new StringContent(someJsonString, Encoding.UTF8, "application/json");

 // here in sync
 using (HttpResponseMessage resultMsg = client.PostAsync(someRequestUrl, jsonEncoded).Result)
 {
  using (HttpContent respContent = resultMsg.Content)
  {
   return respContent.ReadAsStringAsync().Result;
  }
 }
}
7
Bernhard

これがWindowsランタイムアプリケーション用の場合、自己署名証明書をプロジェクトに追加し、appxmanifestで参照する必要があります。

ドキュメントはこちらです: http://msdn.Microsoft.com/en-us/library/windows/apps/hh465031.aspx

信頼されていないCAからのもの(マシン自体が信頼していないプライベートCAなど)の場合も同じです-CAのパブリック証明書を取得し、コンテンツとしてアプリに追加してからマニフェストに追加する必要があります。

それが完了すると、アプリは正しく署名された証明書としてそれを見るでしょう。

6
Oren Novotny

答えはありませんが、代替手段はあります。

Fiddler2 を使用してトラフィックを監視し、HTTPS復号化を有効にすると、開発環境で問題が発生することはありません。 Microsoft SurfaceなどのWinRTデバイスでは、標準のアプリをインストールできないため、これは機能しません。しかし、開発Win8コンピューターは問題ありません。

Fiddler2でHTTPS暗号化を有効にするには、Tools> Fiddler Options> HTTPS(Tab)> Check "Decrypt HTTPS Traffic"に移動します。

誰かがエレガントなソリューションを持っていることを期待して、このスレッドに目を光らせていきます。

2
Laith

私はこれで例を見つけました Kubernetes client 彼らが X509VerificationFlags.AllowUnknownCertificateAuthority を使用して、自己署名自己署名ルート証明書を信頼していました。私たちのPEMでエンコードされたルート証明書で動作するように、サンプルを少し作り直しました。これが誰かの助けになることを願っています。

namespace Utils
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Net.Security;
  using System.Security.Cryptography.X509Certificates;

  /// <summary>
  /// Verifies that specific self signed root certificates are trusted.
  /// </summary>
  public class HttpClientHandler : System.Net.Http.HttpClientHandler
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="HttpClientHandler"/> class.
    /// </summary>
    /// <param name="pemRootCerts">The PEM encoded root certificates to trust.</param>
    public HttpClientHandler(IEnumerable<string> pemRootCerts)
    {
      foreach (var pemRootCert in pemRootCerts)
      {
        var text = pemRootCert.Trim();
        text = text.Replace("-----BEGIN CERTIFICATE-----", string.Empty);
        text = text.Replace("-----END CERTIFICATE-----", string.Empty);
        this.rootCerts.Add(new X509Certificate2(Convert.FromBase64String(text)));
      }

      this.ServerCertificateCustomValidationCallback = this.VerifyServerCertificate;
    }

    private bool VerifyServerCertificate(
      object sender,
      X509Certificate certificate,
      X509Chain chain,
      SslPolicyErrors sslPolicyErrors)
    {
      // If the certificate is a valid, signed certificate, return true.
      if (sslPolicyErrors == SslPolicyErrors.None)
      {
        return true;
      }

      // If there are errors in the certificate chain, look at each error to determine the cause.
      if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) != 0)
      {
        chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;

        // add all your extra certificate chain
        foreach (var rootCert in this.rootCerts)
        {
          chain.ChainPolicy.ExtraStore.Add(rootCert);
        }

        chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
        var isValid = chain.Build((X509Certificate2)certificate);

        var rootCertActual = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
        var rootCertExpected = this.rootCerts[this.rootCerts.Count - 1];
        isValid = isValid && rootCertActual.RawData.SequenceEqual(rootCertExpected.RawData);

        return isValid;
      }

      // In all other cases, return false.
      return false;
    }

    private readonly IList<X509Certificate2> rootCerts = new List<X509Certificate2>();
  }
}
2
PaulB

私はオンラインでうまくいくように見える例を見つけました:

まず、新しい ICertificatePolicy を作成します

using System.Security.Cryptography.X509Certificates;
using System.Net;

public class MyPolicy : ICertificatePolicy
{
  public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, 
int certificateProblem)
  {
    //Return True to force the certificate to be accepted.
    return true;
  }
}

次に、httpリクエストを送信する前に次のように使用します。

System.Net.ServicePointManager.CertificatePolicy = new MyPolicy();

http://www.terminally-incoherent.com/blog/2008/05/05/send-a-https-post-request-with-c/

1
TombMedia