HttpClient के साथ अविश्वसनीय एसएसएल प्रमाणपत्रों की अनुमति


114

मैं एसएसएल पर अपने परीक्षण वेब एपीआई के साथ संवाद करने के लिए अपने विंडोज 8 एप्लिकेशन को प्राप्त करने के लिए संघर्ष कर रहा हूं।

ऐसा लगता है कि HttpClient / HttpClientHandler अविश्वासित प्रमाणपत्रों को अनदेखा करने का विकल्प और विकल्प प्रदान नहीं करता है, जैसे WebRequest आपको सक्षम बनाता है (यद्यपि "hacky" तरीके से ServerCertificateValidationCallback)।

कोई भी सहायताकाफी प्रशंसनीय होगी!


5
यदि आप .NET कोर का उपयोग कर रहे हैं तो आप इस उत्तर में रुचि ले सकते हैं ।
kdaveid

जवाबों:


13

विंडोज 8.1 के साथ, आप अब अवैध SSL सेरेक्ट पर भरोसा कर सकते हैं। आपको या तो Windows.Web.HttpClient का उपयोग करना होगा या यदि आप System.Net.Http.HttpClient का उपयोग करना चाहते हैं, तो आप मेरे द्वारा लिखे गए संदेश हैंडलर एडाप्टर का उपयोग कर सकते हैं: http://www.nuget.org/packages/WinRetHttpClientHandler

डॉक्स GitHub पर हैं: https://github.com/onovotny/WinRtHttpClientHerler


12
क्या आपके सभी कोड का उपयोग किए बिना ऐसा करने का कोई तरीका है? दूसरे शब्दों में, आपके समाधान का सार क्या है?
wensveen

समाधान का सार विंडोज http क्लाइंट हैंडलर को लपेटना है और HttpClient के कार्यान्वयन के रूप में उपयोग करना है। यह सब इस फ़ाइल में है: github.com/onovotny/WinRtHttpClientHandler/blob/master/… इसे कॉपी करने के लिए स्वतंत्र महसूस करें लेकिन यह सुनिश्चित करें कि सिर्फ पैकेज का उपयोग क्यों न करें।
क्लेयर नोवोटनी

@OrenNovotny तो आपका समाधान विंडोज संस्करण के लिए बाध्य नहीं है?
chester89

मैंने इसे अपने UWP ऐप में लागू किया, और मैंने नीचे दिए गए फ़िल्टर उदाहरण का उपयोग किया। मुझे अब भी वही त्रुटि मिलती है।
क्रिश्चियन

158

एक त्वरित और गंदा समाधान ServicePointManager.ServerCertificateValidationCallbackप्रतिनिधि का उपयोग करना है । यह आपको अपना स्वयं का प्रमाणपत्र सत्यापन प्रदान करने की अनुमति देता है। सत्यापन पूरे ऐप डोमेन पर वैश्विक रूप से लागू किया जाता है।

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

मैं मुख्य रूप से उन परिस्थितियों में इकाई परीक्षण के लिए इसका उपयोग करता हूं जहां मैं एक समापन बिंदु के खिलाफ चलना चाहता हूं जिसे मैं प्रक्रिया में होस्ट कर रहा हूं और इसे WCF क्लाइंट या के साथ हिट करने की कोशिश कर रहा हूं HttpClient

उत्पादन कोड के लिए आप अधिक महीन दाने वाला नियंत्रण चाहते हैं WebRequestHandlerऔर इसके ServerCertificateValidationCallbackप्रतिनिधि संपत्ति ( नीचे dtb का जवाब देखें ) का उपयोग करके बेहतर होगा । या ctacke उत्तर का उपयोग कर HttpClientHandler। मैं इन दोनों में से किसी एक को पसंद कर रहा हूं, यहां तक ​​कि अपने एकीकरण परीक्षणों के साथ भी कि मैं इसे कैसे करता था जब तक कि मुझे कोई अन्य हुक नहीं मिलता।


32
नहीं downvoter, लेकिन ServerCertificateValidationCallback के साथ सबसे बड़ी समस्याओं में से एक यह है कि यह मूल रूप से आपके AppDomain के लिए वैश्विक है। इसलिए यदि आप एक पुस्तकालय लिख रहे हैं, जिसे एक अविश्वसनीय प्रमाण पत्र के साथ साइट पर कॉल करने और इस वर्कअराउंड को नियोजित करने की आवश्यकता है, तो आप अपने पुस्तकालय को ही नहीं, बल्कि पूरे एप्लिकेशन के व्यवहार को बदल रहे हैं। इसके अलावा, लोगों को हमेशा 'आँख बंद करके सच' दृष्टिकोण के साथ सावधान रहना चाहिए। इसके गंभीर सुरक्षा निहितार्थ हैं। इसे पढ़े गए / * दिए गए मापदंडों का निरीक्षण करना चाहिए और फिर ध्यान से तय करना चाहिए कि क्या सही है / वापस;
scottt732

@ scottt732 निश्चित रूप से एक मान्य बिंदु और ध्यान देने योग्य है लेकिन यह अभी भी एक वैध समाधान है। शायद ओपी द्वारा मूल प्रश्न को फिर से पढ़ने के बाद ऐसा प्रतीत होता है कि वह पहले से ही ServerCertificateValidationCallback हैंडलर के बारे में जानते थे
कांस्यम्स्की

2
मैं प्रेषक जैसे कुछ मानदंडों पर कम से कम फ़िल्टर करने की सलाह
दूंगा

2
मुझे वास्तव में वैश्विक ServicePointManager बनाम WebRequestHandler विकल्प की सिफारिश करनी है।
थॉमस एस। ट्राएस

3
आपको विश्व स्तर पर ServicePointManager का उपयोग करने की आवश्यकता नहीं है, आप उस सेवा बिंदु को प्राप्त करने के लिए ServicePointManager.GetServicePoint(Uri) ( डॉक्स देखें ) का उपयोग कर सकते हैं जो केवल उस URI के लिए कॉल पर लागू होता है। फिर आप उस सबसेट के आधार पर गुणों को सेट कर सकते हैं और घटनाओं को संभाल सकते हैं।
ओट्सोडा

87

WebRequestHandler Class और उसके ServerCertificateValidationCallback प्रॉपर्टी पर एक नज़र डालें :

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

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

5
प्रतिक्रिया के लिए धन्यवाद, हालांकि मैंने पहले ही उस पर ध्यान दिया है - यह विंडोज 8 स्टोर एप्लिकेशन के लिए .NET में मौजूद नहीं है।
जेमी

हालाँकि, किसी का अपना HttpClientHandler या HttpMessageHandler व्युत्पन्न वर्ग बनाना काफी आसान है, विशेष रूप से इस तथ्य को देखते हुए कि WebRequestHandler स्रोत आसानी से उपलब्ध है।
थॉमस एस। ट्राईस

@ थॉमस। इसके बारे में कोई नमूना? derived class?
किकेनेट

2
का उपयोग कर HttpClientHandler?
किकेनेट

1
@Kiquenet यह उत्तर 2012 से है, यह पहले से ही 6 साल पुराना है, और हाँ - कई बार इन लोगों को यकीन था कि httpclient का उपयोग करने का यह सही तरीका है :)
justmara

63

यदि आप .NET मानक पुस्तकालय में ऐसा करने का प्रयास कर रहे हैं, तो यहां एक सरल समाधान है, जिसमें trueआपके हैंडलर में बस लौटने का जोखिम है । मैं आपकी सुरक्षा छोड़ देता हूं।

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

var client = new HttpClient(handler);

1
प्लेटफ़ॉर्म में यह परिणाम तब नहीं हुआ जब uwp से संदर्भित किया गया
इवान

मेरे लिए UWP में काम किया। शायद समर्थन कवरेज 14 महीनों में परिपक्व हो गया है। ध्यान दें: यह हैक केवल टेस्ट / देव एनवी में आवश्यक होना चाहिए (जहां स्व-हस्ताक्षरित सेर्ट का उपयोग किया जा रहा है)
बेन मैकइंटायर

मैंने इस कोड को चलाया और हमेशा System.NotImplementedException को पूरा करता हूं। मुझे पता नहीं क्यों।
लियू फेंग

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.Webऔर Windows.Web.Httpसाथ में?
किकेनेट

2
HttpClient को .NET मानक या UWP में यह ओवरराइड नहीं लगता है।
क्रिश्चियन

"का उपयोग कर" पैटर्न का उपयोग न करें: docs.microsoft.com/en-us/azure/altecture/antipatterns/…
बर्नहार्ड

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
}

आईडीसॉफ़्टरी इंटरफ़ेस के कारण। कृपया नहीं!

Microsoft आपको बताता है:

और यहाँ आप एक विस्तृत विश्लेषण पा सकते हैं कि पर्दे के पीछे क्या चल रहा है: https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

आपके SSL प्रश्न के बारे में और https://docs.microsoft.com/en-us/azure/ RGBecture/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 धागे को सुरक्षित बनाने के बारे में आपका पूरा जवाब (यहां तक ​​कि इसके वैध माना जाता है)।
आराध्य

1
यह केवल "धागा सुरक्षा" के बारे में नहीं है। मैं "अक्षम" एसएसएल सत्यापन के साथ httpclient के उपयोग का "सही" तरीका दिखाना चाहता था। अन्य उत्तर "वैश्विक रूप से" प्रमाणपत्र प्रबंधक को संशोधित करते हैं।
बर्नहार्ड

7

यदि यह विंडोज रनटाइम एप्लिकेशन के लिए है, तो आपको प्रोजेक्ट में स्व-हस्ताक्षरित प्रमाण पत्र जोड़ना होगा और इसे सन्दर्भ में संदर्भित करना होगा।

डॉक्स यहां हैं: http://msdn.microsoft.com/en-us/library/windows/apps/hh46503131.aspx

एक ही बात अगर यह एक सीए से है जो विश्वसनीय नहीं है (एक निजी सीए की तरह है कि मशीन खुद पर भरोसा नहीं करती है) - आपको सीए के सार्वजनिक प्रमाण पत्र प्राप्त करने की आवश्यकता है, इसे ऐप में सामग्री के रूप में जोड़ें और फिर इसे प्रकट में जोड़ें।

एक बार ऐसा करने के बाद, ऐप इसे एक सही तरीके से हस्ताक्षरित प्रमाण पत्र के रूप में देखेगा।


2

मेरे पास कोई जवाब नहीं है, लेकिन मेरे पास एक विकल्प है।

यदि आप Fiddler2 का उपयोग करते हैं ट्रैफ़िक की निगरानी करने और HTTPS डिक्रिप्शन को सक्षम करने के का , तो आपके विकास का वातावरण शिकायत नहीं करेगा। यह WinRT डिवाइस पर काम नहीं करेगा, जैसे कि Microsoft सरफेस, क्योंकि आप उन पर मानक एप्लिकेशन इंस्टॉल नहीं कर सकते हैं। लेकिन आपका विकास Win8 कंप्यूटर ठीक रहेगा।

Fiddler2 में HTTPS एन्क्रिप्शन को सक्षम करने के लिए, टूल्स> Fiddler Options> HTTPS (टैब)> "डिक्रिप्ट HTTPS ट्रैफिक" पर जाएं।

मैं इस धागे पर अपनी नज़र रखने जा रहा हूँ जिससे किसी को एक सुंदर समाधान की उम्मीद है।


2

मुझे इस Kubernetes क्लाइंट में एक उदाहरण मिला, जहाँ वे स्व-हस्ताक्षरित रूट प्रमाणपत्रों पर भरोसा करने के लिए X509VerificationFlags.AllowUnognCertificateAuthority का उपयोग कर रहे थे । मैंने अपने 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.