วิธีละเว้นการตรวจสอบใบรับรองเมื่อ ssl


132

ฉันกำลังพยายามหาวิธีที่จะเพิกเฉยต่อการตรวจสอบใบรับรองเมื่อขอทรัพยากร Https จนถึงตอนนี้ฉันพบบทความที่เป็นประโยชน์ในอินเทอร์เน็ต

แต่ฉันยังคงมีปัญหาอยู่ โปรดตรวจสอบรหัสของฉัน ฉันไม่เข้าใจว่าโค้ดคืออะไรServicePointManager.ServerCertificateValidationCallbackหมายถึงอะไร

วิธีการมอบหมายนี้จะถูกเรียกใช้เมื่อใด และอีกหนึ่งคำถามฉันควรเขียนโค้ดนี้ในที่ใด ก่อนServicePointManager.ServerCertificateValidationCallbackดำเนินการหรือก่อนStream stream = request.GetRequestStream()?

public HttpWebRequest GetRequest()
{
    CookieContainer cookieContainer = new CookieContainer();

    // Create a request to the server
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_remoteUrl);

    #region Set request parameters

    request.Method = _context.Request.HttpMethod;
    request.UserAgent = _context.Request.UserAgent;
    request.KeepAlive = true;
    request.CookieContainer = cookieContainer;
    request.PreAuthenticate = true;
    request.AllowAutoRedirect = false;

    #endregion

    // For POST, write the post data extracted from the incoming request
    if (request.Method == "POST")
    {
        Stream clientStream = _context.Request.InputStream;
        request.ContentType = _context.Request.ContentType;
        request.ContentLength = clientStream.Length;

        ServicePointManager.ServerCertificateValidationCallback = delegate(
            Object obj, X509Certificate certificate, X509Chain chain, 
            SslPolicyErrors errors)
            {
                return (true);
            };

            Stream stream = request.GetRequestStream();

            ....
        }

        ....

        return request;
    }
}   

คำตอบ:


67

เนื่องจากมีServicePointManagerส่วนกลางเพียงรายเดียวการตั้งค่าServicePointManager.ServerCertificateValidationCallbackจะให้ผลลัพธ์ที่คำขอที่ตามมาทั้งหมดจะสืบทอดนโยบายนี้ เนื่องจากเป็น "การตั้งค่า" ทั่วโลกจึงควรตั้งค่าในเมธอดApplication_StartในGlobal.asax Global.asax

การตั้งค่าการโทรกลับจะแทนที่พฤติกรรมเริ่มต้นและคุณสามารถสร้างรูทีนการตรวจสอบความถูกต้องที่กำหนดเองได้


แล้วลูกค้าที่ไม่มี Global.asax ล่ะ? ฉันกำลังเรียกใช้บริการ REST ที่ทำงานบนเครือข่ายท้องถิ่นจากอุปกรณ์มือถือ
บีเคลย์แชนนอน

3
HttpWebRequestคำถามคือที่เฉพาะเจาะจงเพื่อ หากคุณกำลังใช้วิธีอื่นคุณจะต้องดูในเอกสารว่าจะทำอย่างไรให้สำเร็จ
Sani Singh Huttunen

ฉันใช้ WebRequest ซึ่งถูกส่งไปยัง HttpWebRequest เช่น: ((HttpWebRequest) request) .Accept = contentType;
บีเคลย์แชนนอน

ตามที่ระบุไว้ในคำตอบของฉัน: ขอแนะนำให้ตั้งค่าใน Global.asax ไม่ใช่ข้อกำหนด คุณสามารถตั้งค่าก่อนการโทรไปยังบริการ REST
Sani Singh Huttunen

3
ดูลิงค์นี้สำหรับวิธีแก้ปัญหาที่เป็นไปได้
Sani Singh Huttunen

174

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

String url = "https://www.stackoverflow.com";
HttpWebRequest request = HttpWebRequest.CreateHttp(url);
request.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

ใน. NET 4.0 คุณสามารถใช้ Lambda Expression กับตัวกรองส่วนกลางได้

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

2
มีวิธีแก้ไขตามคำขอสำหรับ FtpWebRequest หรือไม่?
Timo

ดูเหมือนว่าจะมีอยู่ใน 4.0 ของฉัน
Nacht

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

2
การกลับมาtrueเป็นสิ่งที่คุณสามารถทำได้เมื่อทำการทดลองระหว่างการพัฒนาอย่างไรก็ตามมันไม่ปลอดภัย มันควรจะเป็นเงื่อนไข
Fred

1
การใช้งาน(HttpWebRequest)WebRequest.Create(url)นั้นใช้ได้อย่างสมบูรณ์ แต่ในกล่องของฉันHttpWebRequest.Create(url)ยังคงมีอยู่ในโครงการที่กำหนดเป้าหมาย. Net 4.6.2 ทางเลือกของเชฟ แต่ ณ จุดHttpClientนี้น่าจะเป็น API ที่ดีกว่าที่จะใช้
Adam Venezia

53

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                        System.Security.Cryptography.X509Certificates.X509Chain chain,
                        System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        return true; // **** Always accept
    };

ตัวอย่างจากที่นี่: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors


17
ServicePointManager.ServerCertificateValidationCallback + = (ผู้ส่งใบรับรองห่วงโซ่ sslPolicyErrors) => จริง;
David Rutgos

3
การกลับมาจริงเสมอนั้นไม่ปลอดภัย ควรคืนค่าจริงตามเงื่อนไข
Fred

นี่เป็นกระบวนการต่อกระบวนการดังนั้นจึงไม่ปลอดภัย
Mikhail Orlov

25

นอกจากนี้ยังมีโซลูชันตัวแทนสั้น ๆ :

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 

3
การกลับมาเสมอtrueคือความไม่ปลอดภัย
Fred

7
ใช่การเชื่อถือใบรับรอง SSL ทั้งหมดมักไม่ปลอดภัยตามคำจำกัดความ หลีกเลี่ยงการทำเช่นนั้นถ้าเป็นไปได้
Andrej Rommel

@AndrejRommel มีวิธีอะไรแนะนำไหม
Kiquenet

2
วิธีที่แนะนำคือสร้างใบรับรอง SSL ที่ถูกต้องและใช้อย่างเหมาะสมหากคุณมีอำนาจควบคุมเซิร์ฟเวอร์ เราลงเอยด้วยการสร้างโดยใช้ allowencrypt.org
Andrej Rommel

5

มีการพูดถึงว่าก่อนหน้านี้. NET 4.5 คุณสมบัติตามคำร้องขอเข้าถึงServicePointManagerไม่พร้อมใช้งาน

นี่คือรหัส. NET 4.0 ที่จะให้คุณเข้าถึงได้ServicePointตามคำขอ ไม่ให้คุณเข้าถึงการโทรกลับตามคำขอ แต่ควรให้คุณทราบรายละเอียดเพิ่มเติมเกี่ยวกับปัญหา เพียงแค่เข้าถึงคุณสมบัติscvPoint.Certificate(หรือClientCertificateถ้าคุณต้องการ)

WebRequest request = WebRequest.Create(uri);

// oddity: these two .Address values are not necessarily the same!
//  The service point appears to be related to the .Host, not the Uri itself.
//  So, check the .Host vlaues before fussing in the debugger.
//
ServicePoint svcPoint = ServicePointManager.FindServicePoint(uri);
if (null != svcPoint)
{
    if (!request.RequestUri.Host.Equals(svcPoint.Address.Host, StringComparison.OrdinalIgnoreCase))
    {
        Debug.WriteLine(".Address              == " + request.RequestUri.ToString());
        Debug.WriteLine(".ServicePoint.Address == " + svcPoint.Address.ToString());
    }
    Debug.WriteLine(".IssuerName           == " + svcPoint.Certificate.GetIssuerName());
}

ตกลงกัน! แต่แล้ว OP นี้เกี่ยวกับวิธีการของignoreพวกเขาไม่ไว้วางใจพวกเขา
Jesse Chisholm

อย่างไรก็ตามการใช้ServicePointฉันไม่สามารถ เชื่อถือใบรับรอง SSL ทั้งหมดได้ตลอดเวลาหรือไม่เพิกเฉยต่อใบรับรองทั้งหมดเนื่องจากไม่ได้ServerCertificateValidationCallback มอบหมายใน ServicePoint
Kiquenet

4

บังเอิญนี่เป็นวิธีที่ละเอียดน้อยที่สุดในการปิดการตรวจสอบใบรับรองทั้งหมดในแอปที่ฉันรู้จัก:

ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;

4

แทนที่จะเพิ่มการเรียกกลับไปยัง ServicePointManager ซึ่งจะลบล้างการตรวจสอบใบรับรองทั่วโลกคุณสามารถตั้งค่าการโทรกลับบนอินสแตนซ์ภายในของ HttpClient วิธีนี้ควรส่งผลต่อการโทรที่ใช้อินสแตนซ์ของ HttpClient เท่านั้น

นี่คือโค้ดตัวอย่างที่แสดงวิธีการเพิกเฉยต่อข้อผิดพลาดในการตรวจสอบใบรับรองสำหรับเซิร์ฟเวอร์เฉพาะในตัวควบคุม Web API

using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public class MyController : ApiController
{

    // use this HttpClient instance when making calls that need cert errors suppressed
    private static readonly HttpClient httpClient;

    static MyController()
    {
        // create a separate handler for use in this controller
        var handler = new HttpClientHandler();

        // add a custom certificate validation callback to the handler
        handler.ServerCertificateCustomValidationCallback = ((sender, cert, chain, errors) => ValidateCert(sender, cert, chain, errors));

        // create an HttpClient that will use the handler
        httpClient = new HttpClient(handler);
    }

    protected static ValidateCert(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
    {

        // set a list of servers for which cert validation errors will be ignored
        var overrideCerts = new string[]
        {
            "myproblemserver",
            "someotherserver",
            "localhost"
        };

        // if the server is in the override list, then ignore any validation errors
        var serverName = cert.Subject.ToLower();
        if (overrideCerts.Any(overrideName => serverName.Contains(overrideName))) return true;

        // otherwise use the standard validation results
        return errors == SslPolicyErrors.None;
    }

}

สิ่งนี้จะใช้ไม่ได้กับ. NET Core เท่านั้นหรือ (หรือเมื่อใดก็ตามที่เพิ่ม ServerCertificateCustomValidationCallback ใน HttpClientHandler)
phillyslick

โซลูชันนี้ควรใช้งานได้ใน. Net Framework 4.5 และใหม่กว่าเช่นเดียวกับ. Net Core (แม้ว่าฉันจะไม่ได้ทดสอบใน. Net Core)
เชลดอน

@Sheldon นี่เป็นอัญมณี :) ใช้ในการโทร api-localhost ของฉันระหว่าง. net และ. net core app ที่ประสบความสำเร็จ วิธีแก้ปัญหาที่ดีโดยไม่ต้องยอมรับทั้งหมด
ขนาดใหญ่

3

จากคำตอบของ Adam และความคิดเห็นของ Rob ฉันใช้สิ่งนี้:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => certificate.Issuer == "CN=localhost";

ซึ่งกรอง "ละเว้น" ได้บ้าง ผู้ออกรายอื่นสามารถเพิ่มได้ตามความต้องการแน่นอน สิ่งนี้ได้รับการทดสอบใน. NET 2.0 เนื่องจากเราจำเป็นต้องรองรับรหัสเดิมบางอย่าง


@karank ขออภัยที่ตอบช้า - สามารถเพิ่มได้ทุกที่ก่อนการโทรจริงเช่น ก่อนที่จะโทร request.GetResponse () โปรดทราบว่าผู้ออกอาจมีบางอย่างในกรณีของคุณ
Andrej Grobler

3

CA5386: เครื่องมือวิเคราะห์ช่องโหว่จะแจ้งเตือนคุณถึงรหัสเหล่านี้

รหัสที่ถูกต้อง:

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =>
{
   return (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNotAvailable) != SslPolicyErrors.RemoteCertificateNotAvailable;
};

3

สำหรับ. net core

using (var handler = new HttpClientHandler())
{ 
    // allow the bad certificate
    handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => true;
    using (var httpClient = new HttpClient(handler))
    {
        await httpClient.PostAsync("the_url", null);
    }
}

2

แสดงออกอย่างโจ่งแจ้ง ...

ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(CertCheck);

private static bool CertCheck(object sender, X509Certificate cert,
X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
    return true;
}

0

การเพิ่มคำตอบของ Sani และ blak3r ฉันได้เพิ่มสิ่งต่อไปนี้ลงในรหัสเริ่มต้นสำหรับแอปพลิเคชันของฉัน แต่ใน VB:

'** Overriding the certificate validation check.
Net.ServicePointManager.ServerCertificateValidationCallback = Function(sender, certificate, chain, sslPolicyErrors) True

ดูเหมือนจะทำเคล็ดลับ


0

เคล็ดลับ:คุณยังสามารถใช้วิธีนี้เพื่อติดตามใบรับรองที่กำลังจะหมดอายุในไม่ช้า วิธีนี้สามารถช่วยประหยัดเบคอนของคุณหากคุณพบใบรับรองที่กำลังจะหมดอายุและสามารถแก้ไขได้ทันเวลา เหมาะสำหรับ บริษัท บุคคลที่สาม - สำหรับเรานี่คือ DHL / FedEx DHL เพิ่งปล่อยให้ใบรับรองหมดอายุซึ่งจะทำให้เราล่าช้า 3 วันก่อนวันขอบคุณพระเจ้า โชคดีที่แก้ไขได้ ... คราวนี้!

    private static DateTime? _nextCertWarning;
    private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
    {
        if (error == SslPolicyErrors.None)
        {
            var cert2 = cert as X509Certificate2;
            if (cert2 != null)
            { 
                // If cert expires within 2 days send an alert every 2 hours
                if (cert2.NotAfter.AddDays(-2) < DateTime.Now)
                {
                    if (_nextCertWarning == null || _nextCertWarning < DateTime.Now)
                    {
                        _nextCertWarning = DateTime.Now.AddHours(2);

                        ProwlUtil.StepReached("CERT EXPIRING WITHIN 2 DAYS " + cert, cert.GetCertHashString());   // this is my own function
                    }
                }
            }

            return true;
        }
        else
        {
            switch (cert.GetCertHashString())
            {
                // Machine certs - SELF SIGNED
                case "066CF9CAD814DE2097D367F22D3A7E398B87C4D6":    

                    return true;

                default:
                    ProwlUtil.StepReached("UNTRUSTED CERT " + cert, cert.GetCertHashString());
                    return false;
            }
        }
    }

ตรวจสอบให้แน่ใจว่าได้จัดการสถานการณ์ที่กลไกการแจ้งเตือนของคุณอาจมีใบรับรองที่หมดอายุไม่เช่นนั้นคุณจะจบลงด้วย stackoverflow!
Simon_Weaver

คืออะไรProwlUtil.StepReached?
Kiquenet

ขออภัยนั่นเป็นเพียงวิธีการของฉันเองที่เรียก Prowl API ซึ่งสามารถส่งการแจ้งเตือนไปยังโทรศัพท์ของฉันได้ อย่างไรก็ตามคุณต้องการบันทึกเป็นสิ่งที่ดี ฉันชอบที่จะถูกดักฟังโทรศัพท์ของฉันสำหรับสิ่งนี้!
Simon_Weaver

0

หลายคำตอบข้างต้นทำงาน ฉันต้องการแนวทางที่ฉันไม่ต้องทำการเปลี่ยนแปลงโค้ดและไม่ทำให้โค้ดของฉันไม่ปลอดภัย ดังนั้นฉันจึงสร้างรายการที่อนุญาตพิเศษ สามารถเก็บรายการที่อนุญาตไว้ในที่เก็บข้อมูลใดก็ได้ ฉันใช้ไฟล์ config เนื่องจากเป็นรายการที่เล็กมาก

รหัสของฉันอยู่ด้านล่าง

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, error) => {
    return error == System.Net.Security.SslPolicyErrors.None || certificateWhitelist.Contains(cert.GetCertHashString());
};

0

Unity C # เวอร์ชันของโซลูชันนี้:

void Awake()
{
    System.Net.ServicePointManager.ServerCertificateValidationCallback += ValidateCertification;
}

void OnDestroy()
{
    ServerCertificateValidationCallback = null;
}

public static bool ValidateCertification(object sender, X509Certificate certificate, X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    return true;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.