HttpClient ile Güvenilmeyen SSL Sertifikalarına İzin Verme


115

Windows 8 uygulamamın test web API'm ile SSL üzerinden iletişim kurmasını sağlamakta zorlanıyorum.

Görünüşe göre HttpClient / HttpClientHandler, WebRequest gibi güvenilmeyen sertifikaları yok sayma seçeneği sunmuyor ve ("hacky" bir şekilde olsa da ServerCertificateValidationCallback).

Herhangi bir yardım çok takdir edilecektir!


5
.NET Core kullanıyorsanız, bu cevap ilginizi çekebilir .
kdaveid

Yanıtlar:


13

Windows 8.1 ile artık geçersiz SSL sertifikalarına güvenebilirsiniz. Windows.Web.HttpClient veya System.Net.Http.HttpClient kullanmak istiyorsanız, yazdığım ileti işleyici adaptörünü kullanabilirsiniz: http://www.nuget.org/packages/WinRtHttpClientHandler

Dokümanlar GitHub'da: https://github.com/onovotny/WinRtHttpClientHandler


12
Tüm kodunuzu kullanmadan bunu yapmanın bir yolu var mı? Başka bir deyişle, çözümünüzün özü nedir?
wensveen

Çözümün özü, windows http istemci işleyicisini sarmak ve bunu HttpClient uygulaması olarak kullanmaktır. Hepsi bu dosyada: github.com/onovotny/WinRtHttpClientHandler/blob/master/… kopyalamaktan çekinmeyin, ancak neden sadece paketi kullanmadığınızdan emin değilsiniz.
Claire Novotny

@OrenNovotny, böylece çözümünüz Windows sürümüne bağlı değil mi?
chester89

Bunu UWP uygulamamda uyguladım ve aşağıdaki filtre örneğini kullandım. Ben hala aynı hatayı alıyorum.
Christian Findlay

158

Delegeyi kullanmak hızlı ve kirli bir çözümdür ServicePointManager.ServerCertificateValidationCallback. Bu, kendi sertifika doğrulamanızı sağlamanıza olanak tanır. Doğrulama, tüm Uygulama Alanında küresel olarak uygulanır.

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

Bunu esas olarak, süreçte barındırdığım bir uç noktaya karşı çalıştırmak istediğim ve bir WCF istemcisi veya HttpClient.

Üretim kodu için daha ince taneli kontrol isteyebilirsiniz ve WebRequestHandlerve onun ServerCertificateValidationCallbackdelegate özelliğini kullanmanız daha iyi olur ( aşağıdaki dtb'nin cevabına bakın ). Ya ctacke cevap kullanarak HttpClientHandler. Başka bir kanca bulamadığım sürece, bunu nasıl yaptığıma göre, entegrasyon testlerimle şimdi bu ikisinden birini tercih ediyorum.


32
Olumsuz oy veren değil, ancak ServerCertificateValidationCallback ile ilgili en büyük sorunlardan biri, temelde AppDomain'iniz için küresel olmasıdır. Dolayısıyla, güvenilmeyen bir sertifikaya sahip bir siteye çağrı yapması gereken bir kitaplık yazıyorsanız ve bu geçici çözümü kullanırsanız, yalnızca kitaplığınızın değil, tüm uygulamanın davranışını değiştirmiş olursunuz. Ayrıca, insanlar 'körü körüne gerçeğe dön' yaklaşımına her zaman dikkat etmelidir. Ciddi güvenlik etkileri var. Sağlanan parametreleri okumalı / * incelemeli ve sonra * / doğru olup olmayacağına dikkatlice karar vermelidir;
scottt732

@ scottt732 Kesinlikle geçerli bir nokta ve bahsetmeye değer ama yine de geçerli bir çözüm. Belki de OP tarafından orijinal soruyu tekrar okuduktan sonra, ServerCertificateValidationCallback işleyicisinin zaten farkında olduğu anlaşılıyor
Bronumski

2
En azından gönderen gibi bazı kriterlere göre filtrelemenizi tavsiye ederim
Boas Enkler

2
Global ServicePointManager'a karşı WebRequestHandler seçeneğini gerçekten önermem gerekiyor.
Thomas S. Trias

3
ServicePointManager'ı global olarak kullanmak zorunda değilsiniz, yalnızca o URI'ye yapılan aramalar için geçerli olan hizmet noktasını almak için kullanabilirsiniz ServicePointManager.GetServicePoint(Uri) ( belgelere bakın ). Daha sonra bu alt kümeye göre özellikleri ayarlayabilir ve olayları işleyebilirsiniz.
oatsoda

87

WebRequestHandler Sınıfına ve ServerCertificateValidationCallback Özelliğine bir göz atın :

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

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

5
Yanıtınız için teşekkürler, ancak bunu zaten araştırdım - Windows 8 Mağazası uygulamaları için .NET'te mevcut değil.
Jamie

Ancak, kişinin kendi HttpClientHandler veya HttpMessageHandler türetilmiş sınıfını oluşturmak, özellikle WebRequestHandler kaynağının hazır olduğu gerçeği göz önüne alındığında yeterince kolaydır.
Thomas S. Trias

@ ThomasS.Trias bu konuda herhangi bir örnek? derived class?
Kiquenet

2
Kullanıyor HttpClientHandlermusunuz?
Kiquenet

1
@Kiquenet bu yanıt 2012'den geliyor, zaten 6 yaşında ve evet - bu zamanlarda birçok kişi bunun httpclient'i kullanmanın doğru yolu olduğundan
emindi

63

Bunu bir .NET Standard kitaplığında yapmaya çalışıyorsanız true, işleyicinize geri dönmenin tüm risklerini içeren basit bir çözüm burada verilmiştir . Güvenliği sana bırakıyorum.

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

var client = new HttpClient(handler);

1
Bu, platformun uwp
Ivan

benim için UWP'de çalıştı. belki de destek kapsamı 14 ayda olgunlaşmıştır. not: bu hack yalnızca test / dev ortamında gerekli olmalıdır (kendinden imzalı sertifikaların kullanıldığı yerlerde)
Ben McIntyre

Bu kodu çalıştırdım ve her zaman System.NotImplementedException ile karşılaştım. Neden bilmiyorum
Liu Feng

25

Yoksa için kullanabilirsiniz HttpClient içinde Windows.Web.Httpad:

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

Ben kullanabilir miyim System.Net.Http, System.Webve Windows.Web.Httpbirlikte?
Kiquenet

2
HttpClient, .NET Standard veya UWP'de bu geçersiz kılmaya sahip görünmüyor.
Christian Findlay


15

Eğer kullanıyorsanız System.Net.Http.HttpClientdoğru model olduğuna inanıyorum

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

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

8

Buradaki çoğu yanıt, tipik kalıbı kullanmanızı önerir:

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

IDisposable arayüz nedeniyle. Lütfen yapma!

Microsoft size nedenini anlatıyor:

Ve burada perde arkasında neler olup bittiğini ayrıntılı bir analiz bulabilirsiniz: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

SSL sorunuzla ilgili olarak ve https://docs.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation/#how-to-fix-the-problem temel alınarak

İşte kalıbınız:

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

Soru, kendinden imzalı sertifikanın güven ilişkisi içindir. Tüm cevabınız HttpClient iş parçacığını güvenli hale getirmekle ilgili (hatta geçerli olduğu düşünülüyor).
Adarsha

1
Konu sadece "iplik güvenliği" değildir. Httpclient'i "devre dışı bırakılmış" SSL doğrulamasıyla kullanmanın "doğru" yolunu göstermek istedim. Diğer yanıtlar "küresel olarak" sertifika yöneticisini değiştirir.
Bernhard

7

Bu bir Windows Runtime uygulaması içinse, kendinden imzalı sertifikayı projeye eklemeniz ve appxmanifest'te buna referans vermeniz gerekir.

Belgeler burada: http://msdn.microsoft.com/en-us/library/windows/apps/hh465031.aspx

Aynı şey, güvenilmeyen bir CA'dan geliyorsa (makinenin kendisinin güvenmediği özel bir CA gibi) - CA'nın genel sertifikasını almanız, onu uygulamaya içerik olarak eklemeniz ve ardından bildirime eklemeniz gerekir.

Bu tamamlandığında, uygulama bunu doğru şekilde imzalanmış bir sertifika olarak görecek.


2

Bir cevabım yok ama bir alternatifim var.

Trafiği izlemek VE HTTPS Şifre Çözme özelliğini etkinleştirmek için Fiddler2 kullanıyorsanız , geliştirme ortamınız şikayet etmeyecektir. Bu, Microsoft Surface gibi WinRT cihazlarında çalışmayacaktır çünkü bunlara standart uygulamalar yükleyemezsiniz. Ancak geliştirme Win8 bilgisayarınız iyi olacak.

Fiddler2'de HTTPS şifrelemesini etkinleştirmek için Araçlar> Fiddler Seçenekleri> HTTPS (Sekme)> "HTTPS Trafiğinin Şifresini Çöz" seçeneğini işaretleyin .

Birisinin zarif bir çözüme sahip olmasını ümit ederek bu konuya göz kulak olacağım.


2

Bu Kubernetes istemcisinde , kendinden imzalı kendinden imzalı kök sertifikalara güvenmek için X509VerificationFlags.AllowUnknownCertificateAuthority'yi kullandıkları bir örnek buldum . Kendi PEM kodlu kök sertifikalarımızla çalışmak için örneklerini biraz elden geçirdim. Umarım bu birine yardımcı olur.

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

İnternette iyi çalışan bir örnek buldum:

Önce yeni bir ICertificatePolicy oluşturursunuz

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

Ardından, http talebinizi şu şekilde göndermeden önce bunu kullanın:

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

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


1
ServicePointManager.CertificatePolicykullanımdan kaldırıldı: docs.microsoft.com/en-us/dotnet/framework/whats-new/…
schmidlop
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.