program story

HttpClient로 신뢰할 수없는 SSL 인증서 허용

inputbox 2020. 8. 31. 07:45
반응형

HttpClient로 신뢰할 수없는 SSL 인증서 허용


Windows 8 응용 프로그램이 SSL을 통해 테스트 웹 API와 통신하도록하는 데 어려움을 겪고 있습니다.

HttpClient / HttpClientHandler가 제공하지 않는 것으로 보이며 WebRequest와 같은 신뢰할 수없는 인증서를 무시하는 옵션을 사용하면 "해커"방식으로 사용할 수 ServerCertificateValidationCallback있습니다.

어떤 도움이라도 대단히 감사하겠습니다!


Windows 8.1에서는 이제 잘못된 SSL 인증서를 신뢰할 수 있습니다. Windows.Web.HttpClient를 사용하거나 System.Net.Http.HttpClient를 사용하려면 내가 작성한 메시지 처리기 어댑터를 사용할 수 있습니다. http://www.nuget.org/packages/WinRtHttpClientHandler

문서는 GitHub에 있습니다 : https://github.com/onovotny/WinRtHttpClientHandler


빠르고 더러운 해결책은 ServicePointManager.ServerCertificateValidationCallback대리자 를 사용하는 것 입니다. 이를 통해 자체 인증서 유효성 검사를 제공 할 수 있습니다. 유효성 검사는 전체 앱 도메인에 전역 적으로 적용됩니다.

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

주로 호스팅중인 엔드 포인트에 대해 실행하고 WCF 클라이언트 또는 HttpClient.

프로덕션 코드의 경우 더 세밀한 제어를 원할 수 있으며 WebRequestHandler및 해당 ServerCertificateValidationCallbackdelegate 속성을 사용하는 것이 좋습니다 (아래 dtb의 답변 참조 ). 또는 ctacke의 대답은 를 사용하여 HttpClientHandler. 다른 후크를 찾을 수없는 경우를 제외하고는 이전 방식보다 통합 테스트에서도이 두 가지 중 하나를 선호합니다.


WebRequestHandler 클래스ServerCertificateValidationCallback 속성을 살펴보십시오 .

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

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

.NET Standard 라이브러리에서이 작업을 수행하려는 경우 true처리기에서 반환하는 모든 위험이있는 간단한 솔루션 이 있습니다. 나는 당신에게 안전을 맡깁니다.

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

var client = new HttpClient(handler);

또는 네임 스페이스 에서 HttpClient사용할 수 있습니다 Windows.Web.Http.

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)) {
    ...
}

Windows 런타임 애플리케이션 용인 경우 자체 서명 된 인증서를 프로젝트에 추가하고 appxmanifest에서 참조해야합니다.

문서는 여기에 있습니다 : http://msdn.microsoft.com/en-us/library/windows/apps/hh465031.aspx

신뢰할 수없는 CA (예 : 머신 자체가 신뢰하지 않는 사설 CA)의 경우도 마찬가지입니다. CA의 공용 인증서를 가져 와서 앱에 콘텐츠로 추가 한 다음 매니페스트에 추가해야합니다.

완료되면 앱에서 올바르게 서명 된 인증서로 표시됩니다.


여기에서 대부분의 답변은 일반적인 패턴을 사용하도록 제안합니다.

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

IDisposable 인터페이스 때문입니다. 제발 하지마!

Microsoft는 다음과 같은 이유를 알려줍니다.

그리고 여기에서이면에서 일어나는 일에 대한 자세한 분석을 찾을 수 있습니다 : https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

Regarding your SSL question and based on https://docs.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation/#how-to-fix-the-problem

Here is your pattern:

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;
  }
 }
}

I don't have an answer, but I do have an alternative.

If you use Fiddler2 to monitor traffic AND enable HTTPS Decryption, your development environment will not complain. This will not work on WinRT devices, such as Microsoft Surface, because you cannot install standard apps on them. But your development Win8 computer will be fine.

To enable HTTPS encryption in Fiddler2, go to Tools > Fiddler Options > HTTPS (Tab) > Check "Decrypt HTTPS Traffic".

I'm going to keep my eye on this thread hoping for someone to have an elegant solution.


I found an example in this Kubernetes client where they were using X509VerificationFlags.AllowUnknownCertificateAuthority to trust self-signed self-signed root certificates. I slightly reworked their example to work with our own PEM encoded root certificates. Hopefully this helps someone.

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>();
  }
}

I found an example online which seems to work well:

First you create a new 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;
  }
}

Then just use this prior to sending your http request like so:

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

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

참고URL : https://stackoverflow.com/questions/12553277/allowing-untrusted-ssl-certificates-with-httpclient

반응형