.net çekirdeğinde geçersiz SSL sertifikasını atla


104

Bir https sitesine bağlanması gereken bir proje üzerinde çalışıyorum. Her bağlandığımda, kodum istisna atıyor çünkü o sitenin sertifikası güvenilmeyen siteden geliyor. .Net çekirdek http'de sertifika kontrolünü atlamanın bir yolu var mı?

Bu kodu .NET'in önceki sürümünden görmüştüm. Sanırım bunun gibi bir şeye ihtiyacım var.

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

Yanıtlar:


28

ServicePointManager.ServerCertificateValidationCallback, .Net Core'da desteklenmez.

Mevcut durum, gelecek 4.1. * System.Net.Http sözleşmesi (HttpClient) için yeni bir ServerCertificateCustomValidationCallback yöntemi olacağıdır . .NET Core ekibi, 4.1 sözleşmesini şimdi tamamlıyor. Bunu github'da buradan okuyabilirsiniz

System.Net.Http 4.1'in yayın öncesi sürümünü, doğrudan CoreFx'teki kaynakları kullanarak veya MYGET beslemesinde deneyebilirsiniz: https://dotnet.myget.org/gallery/dotnet-core

Güncel WinHttpHandler.ServerCertificateCustomValidationCallback Github tanım


8
Bu yalnızca Windows'ta çalışır. Linux için bir çözümünüz var mı? Teşekkürler.
Vladimir

146

Güncelleme:

Aşağıda belirtildiği gibi, tüm uygulamalar bu geri aramayı desteklemez (yani iOS gibi platformlar). Bu durumda, dokümanların dediği gibi, doğrulayıcıyı açıkça ayarlayabilirsiniz:

handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

Bu, .NET Core 2.2, 3.0 ve 3.1 için de çalışır

Eski cevap , daha fazla kontrole sahip ama atabilir PlatformNotSupportedException:

Bunun gibi anonim bir geri arama işlevi ile bir HTTP çağrısında SSL sertifika kontrolünü geçersiz kılabilirsiniz

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

Ek olarak, bir fabrika modeli kullanmayı öneriyorum HttpClientçünkü bu, hemen elden çıkarılamayan paylaşılan bir nesne ve bu nedenle bağlantılar açık kalacak .


3
.Net Core 1.0 kullanıyorum ve bu benim için çalıştı. Bir uyarı olarak, .Net Core 2.0, bunu MacOSX üzerinde çalıştırmanın bir yolunu sağlayan bir HttpClientözellik eklemiş gibi görünüyor DangerousAcceptAnyServerCertificateValidator. Daha fazla bilgi burada - github.com/dotnet/corefx/pull/19908
Troy Witthoeft

1
Bunu AWS Lambda ile kullanarak .NET Core 1.0, özel bir kök CA sertifikasına sahip dahili bir HTTPS'ye bağlanmamı engelleyen şeyi düzeltti.
QuickNull

Herhangi biri factory patterniçin HttpClient?
Kiquenet

@Kiquenet Sadece GetHttpClientMetodun yapılandırılanı döndürdüğü HttpClientve bir usingblok içinde kullandığı bir fabrika oluşturun.
LuckyLikey

Bu, özellikle tek bir müşterinin kullanımına ayarlanabildiğinden, kabul edilen yanıt olmalıdır.
BinaryPatrick

37

Bununla çözerim:

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

Buraya aynı soruna bir cevap aramak için geldim, ancak NET Core için WCF kullanıyorum. Aynı teknedeyseniz, şunu kullanın:

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

Tüm sertifikalar ve AppDomain için küresel mi?
Kiquenet

@Kiquenet: Öyle olduğuna inanıyorum, evet. Başka bir yerde güncellenmiş bir yanıtı kontrol edin, şimdi daha iyi bir çözüm olabilir. Bir yıl oldu. Sanırım kimlik doğrulayıcısını başka bir şey olmasa bile alt sınıflara ayırabilirsin. Ve hayır, HttpClient için bildiğim yerel bir fabrika yok. Daha fazla işlevselliğe ihtiyacınız varsa, RestClient'e bakın.
Troels Larsen 18

HttpClient'te (.NET Core 3.1) ClientCredentials özelliği yoktur.
Павле

@ Павле: Bu projeyi henüz 3.1'e güncellemedim, ancak böyle bir özellik olmalı: docs.microsoft.com/en-us/dotnet/api/… .
Troels Larsen

@ Павле: Bu yanıt HttpClient ile ilgili değil, WCF Hizmeti tarafından oluşturulan bir istemcidir. ASMX SoapClient'im için de çalıştı, çok teşekkürler!
Jan Zahradník

14

.NetCore'da, services configure yönteminde aşağıdaki kod parçacığını ekleyebilirsiniz, sadece SSL sertifikasını sadece geliştirme ortamında geçtiğimizden emin olmak için bir kontrol ekledim

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
Neden -ve, bu başkalarının mvc.net kodunda önerdiği şeyi tam olarak uyguluyor ve onlar üzerinde puan kazandılar, ben sadece aynı uygulamayı .netCore kodunda gösteriyorum
Sameh

muhtemelen. çünkü herhangi bir açıklaması yok. neden bu yaklaşımın başka herhangi birini devralması gerektiği, Açıklamanın bir parçası olabilecek çağrı bölümüne (diyelim mycontroller.cs) hangi kod yazılmalı. herhangi bir resmi belge / alıntı.
Bhanu Chhabra

Söylediğim gibi, konunun başındaki diğer yorumları gözden
geçirdiyseniz

1
cevaplarını destekleyen metinler ekledikleri için lütfen yönergeleri bir kez daha okuyun. Size yardımcı olabilir, @ moderatörler IMHO'nun tam sorunlarına işaret edebilir.
Bhanu Chhabra

8

.NET Core 2.2 ve Docker Linux kapsayıcılarında kendinden imzalı sertifikalar ve istemci sertifika kimlik doğrulaması ile çalışırken aynı sorunla karşılaştım. Dev Windows makinemde her şey yolunda gitti, ancak Docker'da böyle bir hata aldım:

System.Security.Authentication.AuthenticationException: Doğrulama prosedürüne göre uzak sertifika geçersiz

Neyse ki, sertifika bir zincir kullanılarak oluşturuldu. Tabii ki, bu çözümü her zaman görmezden gelebilir ve yukarıdaki çözümleri kullanabilirsiniz.

İşte benim çözümüm:

  1. Sertifikayı Chrome kullanarak bilgisayarımda P7B formatında kaydettim.

  2. Bu komutu kullanarak sertifikayı PEM formatına dönüştürün:
    openssl pkcs7 -inform DER -outform PEM -in <cert>.p7b -print_certs > ca_bundle.crt

  3. Ca_bundle.crt dosyasını açın ve tüm Konu kayıtlarını silin ve temiz bir dosya bırakın. Aşağıdaki örnek:

    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
  1. Bu satırları Dockerfile'a koyun (son adımlarda):
    # 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. Uygulamada:
    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 yöntemi:

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

Öncelikle ÜRETİMDE KULLANMAYIN

AddHttpClient ara yazılım kullanıyorsanız, bu yararlı olacaktır. Üretim için değil geliştirme amacıyla gerekli olduğunu düşünüyorum. Geçerli bir sertifika oluşturana kadar bu Func'u kullanabilirsiniz.

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

ve gibi uygula

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

3

Tüm sertifikalara izin vermek çok güçlüdür ancak tehlikeli de olabilir. Yalnızca geçerli sertifikalara ve bazı belirli sertifikalara izin vermek istiyorsanız, bu şekilde yapılabilir.

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

Orjinal kaynak:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.