[c#] .net 코어에서 유효하지 않은 SSL 인증서 우회

https 사이트에 연결해야하는 프로젝트를 진행 중입니다. 연결할 때마다 해당 사이트의 인증서가 신뢰할 수없는 사이트에서 온 것이므로 코드에서 예외가 발생합니다. .net core http에서 인증서 확인을 우회하는 방법이 있습니까?

이전 버전의 .NET에서이 코드를 보았습니다. 이런 게 필요한 것 같아요.

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



답변

ServicePointManager.ServerCertificateValidationCallback은 .Net Core에서 지원되지 않습니다.

현재 상황은 곧 출시 될 4.1. * System.Net.Http 계약 (HttpClient)에 대한 새로운 ServerCertificateCustomValidationCallback 메서드 가 될 것입니다 . .NET Core 팀은 현재 4.1 계약을 마무리하고 있습니다. 여기 github 에서 이에 대해 읽을 수 있습니다.

CoreFx 또는 MYGET 피드 ( https://dotnet.myget.org/gallery/dotnet-core) 에서 직접 소스를 사용하여 System.Net.Http 4.1의 시험판 버전을 사용해 볼 수 있습니다.

Github의 현재 WinHttpHandler.ServerCertificateCustomValidationCallback 정의


답변

최신 정보:

아래에서 언급했듯이 모든 구현이이 콜백을 지원하는 것은 아닙니다 (예 : 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즉시 삭제되지 않고 연결이 열린 상태로 유지 되는 공유 객체이기 때문에 팩토리 패턴을 사용하는 것이 좋습니다 .


답변

나는 이것으로 해결한다.

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


답변

동일한 문제에 대한 답을 찾기 위해 여기에 왔지만 NET Core 용 WCF를 사용하고 있습니다. 같은 보트에있는 경우 다음을 사용하십시오.

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


답변

.NetCore에서 services configure method에서 다음 코드 조각을 추가 할 수 있습니다. 개발 환경에서만 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;
              });


답변

.NET Core 2.2 및 Docker Linux 컨테이너에서 자체 서명 된 인증서 및 클라이언트 인증서 인증으로 작업 할 때 동일한 문제에 직면했습니다. 내 dev 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);
}


답변

첫째, 생산에 사용하지 마십시오.

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