Cách bỏ qua kiểm tra chứng chỉ khi ssl


132

Tôi đang cố gắng tìm cách bỏ qua kiểm tra chứng chỉ khi yêu cầu tài nguyên Https, cho đến nay, tôi đã tìm thấy một số bài viết hữu ích trên internet.

Nhưng tôi vẫn có một số vấn đề. Vui lòng xem lại mã của tôi. Tôi chỉ không hiểu ServicePointManager.ServerCertificateValidationCallbacký nghĩa của mã .

Khi nào phương thức đại biểu này sẽ được gọi? Và một câu hỏi nữa, tôi nên viết mã này ở nơi nào? Trước khi ServicePointManager.ServerCertificateValidationCallbackthực hiện hay trước 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;
    }
}   

Câu trả lời:


67

Vì chỉ có một ServicePointManager toàn cầu , nên đặt ServicePointManager.ServerCert veValidationCallback sẽ mang lại kết quả là tất cả các yêu cầu tiếp theo sẽ kế thừa chính sách này. Vì nó là "cài đặt" toàn cầu, nên đặt nó trong phương thức Application_Start trong Global.asax .

Đặt cuộc gọi lại ghi đè hành vi mặc định và bạn có thể tự tạo thói quen xác thực tùy chỉnh.


Còn đối với một khách hàng không có Global.asax thì sao? Tôi đang gọi một dịch vụ REST chạy trên mạng cục bộ từ một thiết bị cầm tay.
B. Clay Shannon

3
Câu hỏi là cụ thể HttpWebRequest. Nếu bạn đang sử dụng bất kỳ phương tiện nào khác, bạn sẽ phải xem tài liệu hướng dẫn cách thực hiện việc này.
Sani Singh Huttunen

Tôi đang sử dụng WebRequest, được truyền tới httpWebRequest, chẳng hạn như: ((httpWebRequest) yêu cầu) .Accept = contentType;
B. Clay Shannon

Như đã nêu trong câu trả lời của tôi: đó là ƯU ĐÃI để đặt nó trong Global.asax không phải là một yêu cầu. Bạn thậm chí có thể đặt nó trước cuộc gọi đến dịch vụ REST.
Sani Singh Huttunen

3
Xem liên kết này cho một giải pháp có thể.
Sani Singh Huttunen

174

Đối với bất kỳ ai quan tâm đến việc áp dụng giải pháp này trên cơ sở mỗi yêu cầu, đây là một tùy chọn và sử dụng biểu thức Lambda. Biểu thức Lambda tương tự cũng có thể được áp dụng cho bộ lọc toàn cầu được đề cập bởi blak3r. Phương pháp này xuất hiện để yêu cầu .NET 4.5.

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

Trong .NET 4.0, Lambda Expression có thể được áp dụng cho bộ lọc toàn cầu như vậy

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

2
Có giải pháp nào cho mỗi yêu cầu cho FtpWebRequest không?
Timo

Nó dường như tồn tại tốt trong 4.0 của tôi
Nacht

Tôi nghĩ rằng cho đến nay là một giải pháp tốt hơn cho biến thể 'toàn cầu', mặc dù tất nhiên tôi có thể hiểu tại sao bạn muốn nó. Cá nhân tôi ủng hộ một nhà máy yêu cầu mà sau đó quản lý cuộc gọi lại xác nhận này. Cảm ơn Adam, giải pháp tốt đẹp.
Thượng nghị sĩ

2
Trở về truelà điều bạn có thể làm khi thử nghiệm trong quá trình phát triển, tuy nhiên nó không an toàn. Nó nên là một điều kiện.
Fred

1
Việc sử dụng (HttpWebRequest)WebRequest.Create(url)là hoàn toàn hợp lệ, nhưng trên hộp của tôi, HttpWebRequest.Create(url)vẫn tồn tại trong một dự án nhắm mục tiêu .Net 4.6.2. Lựa chọn của đầu bếp, nhưng tại thời điểm HttpClientnày có lẽ là API tốt hơn để sử dụng.
Adam Venezuela

53

Điều này làm việc cho tôi:

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

Đoạn trích từ đây: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certert-Errors


17
ServicePointManager.ServerCertertValidationCallback + = (người gửi, chứng chỉ, chuỗi, sslPolicyErrors) => true;
David Rutgos

3
Luôn luôn trở về đúng là không an toàn. Nó nên có điều kiện trở lại đúng sự thật.
Fred

Đây là mỗi quá trình, vì vậy nó không an toàn.
Mikhail Orlov

25

Ngoài ra còn có giải pháp đại biểu ngắn:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 

3
Luôn luôn trở về truelà không an toàn.
Fred

7
Có, luôn luôn tin tưởng tất cả các chứng chỉ SSL là không an toàn theo định nghĩa. Tránh làm như vậy nếu có thể.
Andrej Rommel

@AndrejRommel Bạn nên dùng cách nào?
Kiquenet

2
Cách được đề xuất là tạo chứng chỉ SSL hợp lệ và sử dụng đúng cách nếu bạn có quyền kiểm soát máy chủ. Chúng tôi đã kết thúc việc tạo một cái bằng cách sử dụng allowencrypt.org.
Andrej Rommel

5

Đề cập đã được thực hiện rằng trước .NET 4.5, thuộc tính theo yêu cầu truy cập ServicePointManagerkhông có sẵn.

Đây là mã .NET 4.0 sẽ cung cấp cho bạn quyền truy cập ServicePointtrên cơ sở theo yêu cầu. Nó không cung cấp cho bạn quyền truy cập vào cuộc gọi lại theo yêu cầu, nhưng nó sẽ cho phép bạn tìm hiểu thêm chi tiết về vấn đề. Chỉ cần truy cập các thuộc tính scvPoint.Certificate(hoặc ClientCertificatenếu bạn thích).

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

Đã đồng ý! Nhưng sau đó, OP này là về cách ignorehọ, không tin tưởng họ.
Jesse Chisholm

Dù sao, sử dụng ServicePointTôi không thể luôn tin tưởng tất cả các chứng chỉ SSL, cũng không bỏ qua tất cả các chứng chỉ , vì chưa được ServerCertificateValidationCallback ủy quyền trong ServicePoint
Kiquenet

4

Chỉ là tình cờ, đây là cách tắt tối thiểu tất cả xác thực chứng chỉ trong một ứng dụng nhất định mà tôi biết:

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

4

Thay vì thêm một cuộc gọi lại vào ServicePointManager, nó sẽ ghi đè xác thực chứng chỉ trên toàn cầu, bạn có thể đặt cuộc gọi lại trên một phiên bản cục bộ của HTTPClient. Cách tiếp cận này chỉ ảnh hưởng đến các cuộc gọi được thực hiện bằng cách sử dụng thể hiện đó của HTTPClient.

Dưới đây là mã mẫu cho thấy cách bỏ qua lỗi xác thực chứng chỉ cho các máy chủ cụ thể có thể được triển khai trong bộ điều khiển API Web.

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

}

Điều này không chỉ hoạt động cho .NET Core? (Hoặc bất cứ khi nào ServerCertertCustomValidationCallback được thêm vào HttpClientHandler)?
phillyslick

Giải pháp này sẽ hoạt động trong .Net Framework 4.5 trở lên cũng như .Net Core (mặc dù tôi chưa thử nghiệm nó trong .Net Core).
Sheldon

@Sheldon, đây là một viên ngọc :) Được sử dụng trong các cuộc gọi api localhost của tôi giữa một ứng dụng lõi .net và .net thành công. Cách giải quyết tốt đẹp mà không chấp nhận tất cả.
lớn

3

Dựa trên câu trả lời của Adam và nhận xét của Rob, tôi đã sử dụng:

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

mà lọc "bỏ qua" phần nào. Các tổ chức phát hành khác có thể được thêm vào theo yêu cầu của khóa học. Điều này đã được thử nghiệm trong .NET 2.0 vì chúng tôi cần hỗ trợ một số mã kế thừa.


@karank Xin lỗi vì trả lời trễ - Nó có thể được thêm vào bất cứ nơi nào trước khi cuộc gọi thực sự, ví dụ. trước khi gọi request.GetResponse (). Lưu ý rằng Nhà phát hành có thể chứa một cái gì đó khác trong trường hợp của bạn.
Andrej Grobler

3

CA5386: Các công cụ phân tích lỗ hổng sẽ cảnh báo bạn về các mã này.

Mã chính xác:

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

3

Đối với lõi .net

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

Thể hiện rõ ràng ...

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

Thêm vào câu trả lời của Sani's và blak3r, tôi đã thêm đoạn mã sau vào mã khởi động cho ứng dụng của mình, nhưng trong VB:

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

Có vẻ để làm các mẹo.


0

Mẹo: Bạn cũng có thể sử dụng phương pháp này để theo dõi các chứng chỉ sắp hết hạn. Điều này có thể tiết kiệm thịt xông khói của bạn nếu bạn phát hiện ra một chứng chỉ sắp hết hạn và có thể sửa nó kịp thời. Cũng tốt cho các công ty bên thứ ba - đối với chúng tôi đây là DHL / FedEx. DHL chỉ để một chứng nhận hết hạn sẽ làm chúng tôi khó chịu 3 ngày trước Lễ Tạ ơn. May mắn thay, tôi đang ở đây để sửa nó ... lần này!

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

Đảm bảo xử lý tình huống trong đó cơ chế cảnh báo của bạn có thể có chứng chỉ hết hạn - hoặc bạn sẽ kết thúc với một stackoverflow!
Simon_Weaver

ProwlUtil.StepReached
Kiquenet

Xin lỗi, đó chỉ là phương pháp của riêng tôi để gọi API Prowl có thể gửi thông báo đến điện thoại của tôi. Tuy nhiên bạn muốn đăng nhập nó là tốt. Tôi thích được nghe trộm trên điện thoại của tôi cho những thứ như thế này!
Simon_Weaver

0

Một số câu trả lời trên công việc. Tôi muốn một cách tiếp cận mà tôi không phải tiếp tục thay đổi mã và không làm cho mã của tôi không an toàn. Do đó tôi đã tạo ra một danh sách trắng. Danh sách trắng có thể được duy trì trong bất kỳ kho dữ liệu nào. Tôi đã sử dụng tập tin cấu hình vì nó là một danh sách rất nhỏ.

Mã của tôi ở dưới.

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

0

Phiên bản Unity C # của giải pháp này:

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.