bỏ qua chứng chỉ SSL không hợp lệ trong lõi .net


104

Tôi đang thực hiện một dự án cần kết nối với trang https. Mỗi khi tôi kết nối, mã của tôi ném ra ngoại lệ vì chứng chỉ của trang web đó đến từ trang web không đáng tin cậy. Có cách nào để bỏ qua kiểm tra chứng chỉ trong http .net core không?

Tôi đã thấy mã này từ phiên bản .NET trước. Tôi đoán tôi chỉ cần một cái gì đó như thế này.

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

Câu trả lời:


28

ServicePointManager.ServerCertificateValidationCallback không được hỗ trợ trong .Net Core.

Tình hình hiện tại là nó sẽ là một phương thức ServerCertificateCustomValidationCallback mới cho 4.1. * System.Net.Http hợp đồng (HttpClient) sắp tới. .NET Core hiện đang hoàn thiện hợp đồng 4.1. Bạn có thể đọc về điều này tại đây trên github

Bạn có thể dùng thử phiên bản phát hành trước của System.Net.Http 4.1 bằng cách sử dụng các nguồn trực tiếp tại đây trong CoreFx hoặc trên nguồn cấp dữ liệu MYGET: https://dotnet.myget.org/gallery/dotnet-core

Định nghĩa WinHttpHandler.ServerCertificateCustomValidationCallback hiện tại trên Github


8
Điều này chỉ hoạt động trên Windows. Bạn có giải pháp cho Linux không? Cảm ơn.
Vladimir

146

Cập nhật:

Như đã đề cập bên dưới, không phải tất cả các triển khai đều hỗ trợ gọi lại này (tức là các nền tảng như iOS). Trong trường hợp này, như tài liệu nói, bạn có thể đặt trình xác thực một cách rõ ràng:

handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

Điều này cũng hoạt động cho .NET Core 2.2, 3.0 và 3.1

Câu trả lời cũ , có nhiều quyền kiểm soát hơn nhưng có thể ném PlatformNotSupportedException:

Bạn có thể ghi đè kiểm tra chứng chỉ SSL trên cuộc gọi HTTP bằng chức năng gọi lại ẩn danh như thế này

using (var httpClientHandler = new HttpClientHandler())
{
   httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
   using (var client = new HttpClient(httpClientHandler))
   {
       // Make your request...
   }
}

Ngoài ra, tôi khuyên bạn nên sử dụng factory pattern HttpClientvì nó là một đối tượng dùng chung có thể không được xử lý ngay lập tức và do đó các kết nối sẽ vẫn mở .


3
Tôi đang sử dụng .Net Core 1.0 và điều này phù hợp với tôi. Đầu tiên, có vẻ như .Net Core 2.0 đã thêm một thuộc HttpClienttính được gọi là DangerousAcceptAnyServerCertificateValidatorcung cấp một cách để làm cho điều này hoạt động trên MacOSX. Thông tin thêm tại đây - github.com/dotnet/corefx/pull/19908
Troy Witthoeft

1
Sử dụng điều này với AWS Lambda, .NET Core 1.0 đã khắc phục điều gì đang ngăn tôi kết nối với HTTPS nội bộ bằng chứng chỉ CA gốc tùy chỉnh.
QuickNull

Bất kỳ factory patterncho HttpClient?
Kiquenet

@Kiquenet Chỉ cần tạo một nhà máy, nơi GetHttpClientPhương thức trả về cấu hình HttpClientvà sử dụng nó trong một using-block.
LuckyLikey

Đây phải là câu trả lời được chấp nhận, đặc biệt là vì nó có thể được áp dụng cho một khách hàng duy nhất.
BinaryPatrick

37

Tôi giải quyết vấn đề này:

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpClient("HttpClientWithSSLUntrusted").ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            ClientCertificateOptions = ClientCertificateOption.Manual,
            ServerCertificateCustomValidationCallback =
            (httpRequestMessage, cert, cetChain, policyErrors) =>
            {
                return true;
            }
        });

YourService.cs

public UserService(IHttpClientFactory clientFactory, IOptions<AppSettings> appSettings)
    {
        _appSettings = appSettings.Value;
        _clientFactory = clientFactory;
    }

var request = new HttpRequestMessage(...

var client = _clientFactory.CreateClient("HttpClientWithSSLUntrusted");

HttpResponseMessage response = await client.SendAsync(request);

32

Đến đây để tìm câu trả lời cho cùng một vấn đề, nhưng tôi đang sử dụng WCF cho NET Core. Nếu bạn ở cùng thuyền, hãy sử dụng:

client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = 
    new X509ServiceCertificateAuthentication()
    {
        CertificateValidationMode = X509CertificateValidationMode.None,
        RevocationMode = X509RevocationMode.NoCheck
    };

Toàn cầu cho tất cả các chứng chỉ và AppDomain?
Kiquenet

@Kiquenet: Tôi tin như vậy, vâng. Kiểm tra câu trả lời cập nhật ở nơi khác, có thể có một giải pháp tốt hơn bây giờ. Đã được một năm. Tôi đoán bạn có thể phân lớp trình xác thực nếu không có gì khác. Và không, không có nhà máy gốc nào cho HttpClient mà tôi biết. Nếu bạn cần thêm chức năng, hãy xem RestClient.
Troels Larsen

Không có thuộc tính ClientCredentials trong HttpClient (.NET Core 3.1).
Павле

@ Павле: Tôi chưa cập nhật dự án này lên 3.1, nhưng phải có một thuộc tính như vậy: docs.microsoft.com/en-us/dotnet/api/… .
Troels Larsen

@ Павле: Câu trả lời này không phải về HttpClient mà là một ứng dụng khách được tạo Dịch vụ WCF. Cũng đã làm việc cho ASMX SoapClient của tôi, cảm ơn rất nhiều!
Jan Zahradník

14

Trong .NetCore, bạn có thể thêm đoạn mã sau tại phương pháp cấu hình dịch vụ, tôi đã thêm một kiểm tra để đảm bảo rằng chúng tôi chỉ vượt qua chứng chỉ SSL trong môi trường phát triển mà thôi

services.AddHttpClient("HttpClientName", client => {
// code to configure headers etc..
}).ConfigurePrimaryHttpMessageHandler(() => {
                  var handler = new HttpClientHandler();
                  if (hostingEnvironment.IsDevelopment())
                  {
                      handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
                  }
                  return handler;
              });

1
Tại sao lại là -ve, đây là cách triển khai chính xác những gì người khác đề xuất trong mã mvc.net và họ đã ghi điểm trên đó, tôi chỉ đang minh họa cách triển khai tương tự trong mã .netCore
Sameh

có lẽ. bởi vì nó thiếu bất kỳ lời giải thích nào. tại sao cách tiếp cận này nên được tiếp quản bất kỳ cách nào khác, Mã nào nên được viết trong phần gọi (giả sử mycontroller.cs), có thể là một phần của giải thích. bất kỳ tài liệu / trích dẫn chính thức nào.
Bhanu Chhabra

Như tôi đã nói nếu bạn xem xét các nhận xét khác ở đầu chủ đề thì không có nhiều sự khác biệt và họ đã ghi được 18 và 81 điểm,
Sameh

1
bởi vì họ đã thêm văn bản hỗ trợ câu trả lời của họ, vui lòng đọc hướng dẫn một lần nữa. Có thể giúp bạn, @moderator có thể chỉ ra các vấn đề chính xác IMHO.
Bhanu Chhabra

8

Tôi đã gặp phải vấn đề tương tự khi làm việc với chứng chỉ tự ký và xác thực chứng chỉ ứng dụng khách trên các vùng chứa .NET Core 2.2 và Docker Linux. Mọi thứ hoạt động tốt trên máy Windows dev của tôi, nhưng trong Docker, tôi gặp lỗi như vậy:

System.Security.Authentication.AuthenticationException: Chứng chỉ từ xa không hợp lệ theo quy trình xác thực

May mắn thay, chứng chỉ được tạo bằng chuỗi. Tất nhiên, bạn luôn có thể bỏ qua giải pháp này và sử dụng các giải pháp trên.

Vì vậy, đây là giải pháp của tôi:

  1. Tôi đã lưu chứng chỉ bằng Chrome trên máy tính của mình ở định dạng P7B .

  2. Chuyển đổi chứng chỉ sang định dạng PEM bằng lệnh này:
    openssl pkcs7 -inform DER -outform PEM -in <cert>.p7b -print_certs > ca_bundle.crt

  3. Mở tệp ca_bundle.crt và xóa tất cả các bản ghi Chủ đề, để lại một tệp sạch. Ví dụ bên dưới:

    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    _BASE64 DATA_
    -----END CERTIFICATE-----
  1. Đặt những dòng này vào Dockerfile (trong các bước cuối cùng):
    # Update system and install curl and ca-certificates
    RUN apt-get update && apt-get install -y curl && apt-get install -y ca-certificates
    # Copy your bundle file to the system trusted storage
    COPY ./ca_bundle.crt /usr/local/share/ca-certificates/ca_bundle.crt
    # During docker build, after this line you will get such output: 1 added, 0 removed; done.
    RUN update-ca-certificates
  1. Trong ứng dụng:
    var address = new EndpointAddress("https://serviceUrl");                
    var binding = new BasicHttpsBinding
    {
        CloseTimeout = new TimeSpan(0, 1, 0),
        OpenTimeout = new TimeSpan(0, 1, 0),
        ReceiveTimeout = new TimeSpan(0, 1, 0),
        SendTimeout = new TimeSpan(0, 1, 0),
        MaxBufferPoolSize = 524288,
        MaxBufferSize = 65536,
        MaxReceivedMessageSize = 65536,
        TextEncoding = Encoding.UTF8,
        TransferMode = TransferMode.Buffered,
        UseDefaultWebProxy = true,
        AllowCookies = false,
        BypassProxyOnLocal = false,
        ReaderQuotas = XmlDictionaryReaderQuotas.Max,
        Security =
        {
            Mode = BasicHttpsSecurityMode.Transport,
            Transport = new HttpTransportSecurity
            {
                ClientCredentialType = HttpClientCredentialType.Certificate,
                ProxyCredentialType = HttpProxyCredentialType.None
            }
        }
    };
    var client = new MyWSClient(binding, address);
    client.ClientCredentials.ClientCertificate.Certificate = GetClientCertificate("clientCert.pfx", "passwordForClientCert");
    // Client certs must be installed
    client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication
    {
        CertificateValidationMode = X509CertificateValidationMode.ChainTrust,
        TrustedStoreLocation = StoreLocation.LocalMachine,
        RevocationMode = X509RevocationMode.NoCheck
    };

Phương thức GetClientCertificate:

private static X509Certificate2 GetClientCertificate(string clientCertName, string password)
{
    //Create X509Certificate2 object from .pfx file
    byte[] rawData = null;
    using (var f = new FileStream(Path.Combine(AppContext.BaseDirectory, clientCertName), FileMode.Open, FileAccess.Read))
    {
        var size = (int)f.Length;
        var rawData = new byte[size];
        f.Read(rawData, 0, size);
        f.Close();
    }
    return new X509Certificate2(rawData, password);
}

4

Thứ nhất, KHÔNG SỬ DỤNG NÓ TRONG SẢN XUẤT

Nếu bạn đang sử dụng phần mềm trung gian AddHttpClient, điều này sẽ rất hữu ích. Tôi nghĩ rằng nó cần thiết cho mục đích phát triển chứ không phải sản xuất. Cho đến khi bạn tạo chứng chỉ hợp lệ, bạn có thể sử dụng Hàm này.

Func<HttpMessageHandler> configureHandler = () =>
        {
            var bypassCertValidation = Configuration.GetValue<bool>("BypassRemoteCertificateValidation");
            var handler = new HttpClientHandler();
            //!DO NOT DO IT IN PRODUCTION!! GO AND CREATE VALID CERTIFICATE!
            if (bypassCertValidation)
            {
                handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, x509Certificate2, x509Chain, sslPolicyErrors) =>
                {
                    return true;
                };
            }
            return handler;
        };

và áp dụng nó như

services.AddHttpClient<IMyClient, MyClient>(x => { x.BaseAddress = new Uri("https://localhost:5005"); })
        .ConfigurePrimaryHttpMessageHandler(configureHandler);

3

Cho phép tất cả các chứng chỉ là rất mạnh mẽ nhưng nó cũng có thể nguy hiểm. Nếu bạn chỉ muốn cho phép các chứng chỉ hợp lệ cộng với một số chứng chỉ nhất định, nó có thể được thực hiện như thế này.

using (var httpClientHandler = new HttpClientHandler())
{
    httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => {
        if (sslPolicyErrors == SslPolicyErrors.None)
        {
            return true;   //Is valid
        }

        if (cert.GetCertHashString() == "99E92D8447AEF30483B1D7527812C9B7B3A915A7")
        {
            return true;
        }
        return false;
    };
    using (var httpClient = new HttpClient(httpClientHandler))
    {
        var httpResponse = httpClient.GetAsync("https://example.com").Result;
    }
}

Nguồn chính thức:

https://stackoverflow.com/a/44140506/3850405

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.