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


114

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

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

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


5
.NET Core를 사용하는 경우이 답변에 관심 있을 수 있습니다 .
kdaveid

답변:


13

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

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


12
모든 코드를 사용하지 않고이 작업을 수행 할 수있는 방법이 있습니까? 즉, 솔루션의 요지는 무엇입니까?
wensveen

솔루션의 요점은 Windows http 클라이언트 처리기를 래핑하고이를 HttpClient의 구현으로 사용하는 것입니다. 모두이 파일에 있습니다. github.com/onovotny/WinRtHttpClientHandler/blob/master/… 자유롭게 복사 할 수 있지만 패키지를 사용하지 않는 이유는 확실하지 않습니다.
Claire Novotny 2015 년

@OrenNovotny 그래서 솔루션이 Windows 버전에 묶여 있지 않습니까?
chester89

내 UWP 앱에서이를 구현했고 아래 필터 예제를 사용했습니다. 여전히 같은 오류가 발생합니다.
Christian Findlay

158

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

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

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

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


32
다운 보 터는 아니지만 ServerCertificateValidationCallback의 가장 큰 문제 중 하나는 기본적으로 AppDomain에 전역 적이라는 것입니다. 따라서 신뢰할 수없는 인증서로 사이트를 호출하고이 해결 방법을 사용하는 데 필요한 라이브러리를 작성하는 경우 라이브러리뿐만 아니라 전체 응용 프로그램의 동작을 변경하는 것입니다. 또한 사람들은 항상 '맹목적으로 진실을 반환'하는 접근 방식에주의해야합니다. 보안에 심각한 영향을 미칩니다. / * 제공된 매개 변수를 검사 한 다음 * / true를 반환할지 여부를 신중하게 결정해야합니다.
scottt732

@ scottt732 확실히 유효한 포인트이며 언급할만한 가치가 있지만 여전히 유효한 솔루션입니다. 아마도 다시는 그가 이미 ServerCertificateValidationCallback 처리기 알고 있었다 나타나는 OP에 의해 원래의 질문을 읽은 후
Bronumski

2
내가 보낸 사람과 같은 몇 가지 기준에 적어도 필터에 추천 할 것입니다
보아스 Enkler에게

2
WebRequestHandler 옵션과 전역 ServicePointManager를 정말 추천해야합니다.
Thomas S. Trias

3
ServicePointManager를 전역 적으로 사용할 필요는 없습니다 . 해당 URI에 대한 호출에만 적용되는 서비스 지점을 가져 오기 위해 사용 ServicePointManager.GetServicePoint(Uri) ( docs 참조 ) 할 수 있습니다. 그런 다음 속성을 설정하고 해당 하위 집합을 기반으로 이벤트를 처리 할 수 ​​있습니다.
oatsoda

87

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

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

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

5
응답 해 주셔서 감사합니다. 그러나 이미 살펴 보았습니다. Windows 8 Store 앱용 .NET에는 없습니다.
Jamie

그러나 자신의 HttpClientHandler 또는 HttpMessageHandler 파생 클래스를 만드는 것은 특히 WebRequestHandler 소스를 즉시 사용할 수 있다는 사실을 감안할 때 충분히 쉽습니다.
Thomas S. Trias

@ ThomasS.Trias 그것에 대한 샘플이 있습니까? derived class?
Kiquenet

2
사용 HttpClientHandler?
Kiquenet

1
@Kiquenet이 답변은 2012 년부터, 이미 6 살이되었습니다. 그렇습니다. 많은 사람들이 httpclient를 사용하는 올바른 방법이라고 확신했습니다. :)
justmara

63

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

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

var client = new HttpClient(handler);

1
이로 인해 uwp에서 참조 할 때 플랫폼이 지원되지 않습니다
Ivan

UWP에서 나를 위해 일했습니다. 지원 범위가 14 개월 만에 성숙되었을 것입니다. 참고 :이 해킹 테스트에 필요하다면 / dev에 ENV 만 (자체 서명 인증서 표시가 사용되는 경우)
벤 매킨타이어

이 코드를 실행하고 항상 System.NotImplementedException을 충족합니다. 이유를 모르겠습니다.
Liu Feng

25

또는 네임 스페이스 에서 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)) {
    ...
}

내가 사용할 수 System.Net.Http, System.WebWindows.Web.Http함께?
Kiquenet

2
HttpClient는 .NET Standard 또는 UWP에서이 재정의가없는 것 같습니다.
Christian Findlay

"사용"패턴을 사용하지 마십시오 : docs.microsoft.com/en-us/azure/architecture/antipatterns/…
Bernhard

15

사용하는 경우 System.Net.Http.HttpClient올바른 패턴이

var handler = new HttpClientHandler() 
{ 
    ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};

var http = new HttpClient(handler);
var res = http.GetAsync(url);

8

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

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

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

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

그리고 여기서이면에서 일어나는 일에 대한 자세한 분석을 찾을 수 있습니다. 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;
  }
 }
}

문제는 자체 서명 된 인증서의 신뢰 관계에 대한 것입니다. 귀하의 전체 답변은 HttpClient 스레드를 안전하게 만드는 것입니다.
Adarsha

1
"스레드 안전성"만이 아닙니다. "사용 안 함"SSL 확인과 함께 httpclient를 사용하는 "올바른"방법을 보여주고 싶었습니다. 다른 답변은 "전역 적으로"인증서 관리자를 수정합니다.
Bernhard

7

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

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

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

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


2

답은 없지만 대안이 있습니다.

Fiddler2 를 사용 하여 트래픽을 모니터링하고 HTTPS 복호화를 활성화하면 개발 환경이 불평하지 않습니다. 표준 앱을 설치할 수 없기 때문에 Microsoft Surface와 같은 WinRT 장치에서는 작동하지 않습니다. 그러나 개발 Win8 컴퓨터는 괜찮습니다.

Fiddler2에서 HTTPS 암호화를 활성화하려면 도구> Fiddler 옵션> HTTPS (Tab) 로 이동하여 "HTTPS 트래픽 해독"을 선택합니다. 합니다.

누군가가 우아한 해결책을 갖기를 바라면서이 스레드를 계속 주시 할 것입니다.


2

Kubernetes 클라이언트 에서 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>();
  }
}

1

온라인에서 잘 작동하는 예를 찾았습니다.

먼저 새 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
ServicePointManager.CertificatePolicy더 이상 사용되지 않음 : docs.microsoft.com/en-us/dotnet/framework/whats-new/…
schmidlop
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.