อนุญาตใบรับรอง SSL ที่ไม่น่าเชื่อถือกับ HttpClient


115

ฉันกำลังดิ้นรนเพื่อให้แอปพลิเคชัน Windows 8 สื่อสารกับเว็บ API ทดสอบของฉันผ่าน SSL

ดูเหมือนว่า HttpClient / HttpClientHandler ไม่ได้ให้และตัวเลือกในการละเว้นใบรับรองที่ไม่น่าเชื่อถือเช่น WebRequest ช่วยให้คุณสามารถ (แม้ว่าจะเป็นวิธีที่ "แฮ็ก" ServerCertificateValidationCallbackก็ตาม)

ความช่วยเหลือใด ๆ จะได้รับการชื่นชมมาก!


5
ในกรณีที่คุณกำลังใช้ .NET หลักที่คุณอาจจะสนใจในการนี้คำตอบ
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

ส่วนสำคัญของการแก้ปัญหาคือการรวมตัวจัดการไคลเอ็นต์ http ของ windows และใช้เป็นการนำ HttpClient ไปใช้งาน ทุกอย่างอยู่ในไฟล์นี้: github.com/onovotny/WinRtHttpClientHandler/blob/master/…อย่าลังเลที่จะคัดลอกลงใน แต่ไม่แน่ใจว่าทำไมไม่ใช้แพคเกจ
Claire Novotny

@OrenNovotny ดังนั้นการแก้ปัญหาของคุณจึงไม่ผูกมัดกับเวอร์ชัน Windows?
chester89

ฉันใช้สิ่งนี้ในแอป UWP ของฉันและฉันใช้ตัวอย่างตัวกรองด้านล่าง ฉันยังคงได้รับข้อผิดพลาดเดิม
Christian Findlay

158

วิธีแก้ปัญหาที่รวดเร็วและสกปรกคือการใช้ServicePointManager.ServerCertificateValidationCallbackผู้รับมอบสิทธิ์ ซึ่งช่วยให้คุณสามารถตรวจสอบใบรับรองของคุณเองได้ การตรวจสอบความถูกต้องถูกนำไปใช้ทั่วโลกในโดเมนของแอปทั้งหมด

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

ฉันใช้สิ่งนี้เป็นหลักสำหรับการทดสอบหน่วยในสถานการณ์ที่ฉันต้องการรันกับปลายทางที่ฉันกำลังโฮสต์อยู่และกำลังพยายามตีด้วยไคลเอนต์ WCFหรือHttpClient.

สำหรับรหัสการผลิตคุณอาจต้องการการควบคุมที่ละเอียดยิ่งขึ้นและจะเป็นการดีกว่าหากใช้คุณสมบัติWebRequestHandlerและServerCertificateValidationCallbackตัวแทนของรหัส (ดูคำตอบของ dtb ด้านล่าง ) หรือคำตอบ ctacke โดยใช้HttpClientHandler. ตอนนี้ฉันกำลังเลือกอย่างใดอย่างหนึ่งในสองอย่างนี้แม้ว่าจะมีการทดสอบการรวมของฉันมากกว่าวิธีที่ฉันเคยทำเว้นแต่ฉันจะไม่พบตะขออื่น ๆ


32
ไม่ใช่ผู้โหวตลงคะแนน แต่ปัญหาที่ใหญ่ที่สุดอย่างหนึ่งของ ServerCertificateValidationCallback คือโดยทั่วไปแล้ว AppDomain ของคุณจะใช้งานได้ทั่วโลก ดังนั้นหากคุณกำลังเขียนไลบรารีที่ต้องโทรไปยังไซต์ที่มีใบรับรองที่ไม่น่าเชื่อถือและใช้วิธีแก้ปัญหานี้แสดงว่าคุณกำลังเปลี่ยนการทำงานของแอปพลิเคชันทั้งหมดไม่ใช่เฉพาะไลบรารีของคุณ นอกจากนี้ผู้คนควรระมัดระวังกับวิธีการ "กลับสุ่มสี่สุ่มห้า" มีผลกระทบด้านความปลอดภัยอย่างร้ายแรง ควรอ่าน / * ตรวจสอบพารามิเตอร์ที่ให้มาจากนั้นตัดสินใจอย่างรอบคอบว่าจะ * / ส่งคืนจริงหรือไม่
scottt732

@ scottt732 แน่นอนว่าเป็นจุดที่ถูกต้องและควรค่าแก่การกล่าวถึง แต่ก็ยังเป็นวิธีแก้ปัญหาที่ถูกต้อง บางทีหลังจากอ่านคำถามเดิมของ OP แล้วดูเหมือนว่าเขารับรู้ถึงตัวจัดการ
ServerCertificateValidationCallback แล้ว

2
อย่างน้อยฉันอยากจะแนะนำให้กรองเกณฑ์บางอย่างเช่นผู้ส่ง
Boas Enkler

2
ฉันต้องแนะนำตัวเลือก WebRequestHandler เทียบกับ ServicePointManager ระดับโลกจริงๆ
Thomas S. Trias

3
คุณไม่จำเป็นต้องใช้ ServicePointManager ทั่วโลกคุณสามารถใช้ServicePointManager.GetServicePoint(Uri) (ดูเอกสาร ) เพื่อรับจุดบริการที่ใช้กับการโทรไปยัง URI นั้นเท่านั้น จากนั้นคุณสามารถตั้งค่าคุณสมบัติและจัดการเหตุการณ์ตามชุดย่อยนั้นได้
oatsoda

87

ดูที่WebRequestHandler Classและคุณสมบัติ ServerCertificateValidationCallback :

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

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

5
ขอบคุณสำหรับการตอบกลับอย่างไรก็ตามฉันได้ตรวจสอบแล้ว - ไม่มีอยู่ในแอป. NET สำหรับ Windows 8 Store
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 เท่านั้น (ซึ่งใช้ใบรับรองที่ลงนามด้วยตนเอง)
Ben McIntyre

ฉันรันโค้ดนี้และพบกับ 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.WebและWindows.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
ไม่ใช่เรื่อง "ความปลอดภัยของด้าย" เท่านั้น ฉันต้องการแสดงวิธีการใช้ httpclient ที่ "ถูกต้อง" ด้วยการยืนยัน SSL แบบ "ปิดใช้งาน" คำตอบอื่น ๆ "ทั่วโลก" แก้ไขตัวจัดการใบรับรอง
Bernhard

7

หากเป็นแอปพลิเคชัน Windows Runtime คุณต้องเพิ่มใบรับรองที่ลงนามด้วยตนเองลงในโครงการและอ้างอิงใน appxmanifest

เอกสารอยู่ที่นี่: http://msdn.microsoft.com/en-us/library/windows/apps/hh465031.aspx

เช่นเดียวกันหากมาจาก CA ที่ไม่น่าเชื่อถือ (เช่น CA ส่วนตัวที่เครื่องไม่เชื่อถือ) คุณต้องได้รับใบรับรองสาธารณะของ CA เพิ่มเป็นเนื้อหาในแอปจากนั้นเพิ่มลงในไฟล์ Manifest

เมื่อเสร็จแล้วแอปจะเห็นเป็นใบรับรองที่ลงนามอย่างถูกต้อง


2

ฉันไม่มีคำตอบ แต่ฉันมีทางเลือกอื่น

หากคุณใช้Fiddler2เพื่อตรวจสอบปริมาณการใช้งานและเปิดใช้งานการถอดรหัส HTTPS สภาพแวดล้อมการพัฒนาของคุณจะไม่บ่น สิ่งนี้จะไม่ทำงานบนอุปกรณ์ WinRT เช่น Microsoft Surface เนื่องจากคุณไม่สามารถติดตั้งแอปมาตรฐานบนอุปกรณ์เหล่านี้ได้ แต่การพัฒนาคอมพิวเตอร์ Win8 ของคุณจะไม่เป็นไร

เมื่อต้องการเปิดใช้การเข้ารหัส HTTPS ใน Fiddler2 ไปที่เครื่องมือ> ตัวเลือกไวโอลิน> HTTPS (แท็บ)> ตรวจสอบ "ถอดรหัส HTTPS จราจร"

ฉันจะจับตาดูหัวข้อนี้โดยหวังว่าจะมีใครสักคนที่มีทางออกที่ดี


2

ฉันพบตัวอย่างในไคลเอ็นต์ Kubernetesนี้ซึ่งพวกเขาใช้X509VerificationFlags.A 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.