Bagaimana mengabaikan cek sertifikat ketika ssl

132

Saya mencoba menemukan cara untuk mengabaikan pemeriksaan sertifikat ketika meminta sumber daya Https, sejauh ini, saya menemukan beberapa artikel bermanfaat di internet.

Tetapi saya masih memiliki beberapa masalah. Harap tinjau kode saya. Saya hanya tidak mengerti apa artinya kode ServicePointManager.ServerCertificateValidationCallback.

Kapan metode delegasi ini dipanggil? Dan satu pertanyaan lagi, di tempat mana saya harus menulis kode ini? Sebelum ServicePointManager.ServerCertificateValidationCallbackdieksekusi atau sebelumnya 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;
    }
}   
Joe.wang
sumber
Kemungkinan rangkap C # Abaikan kesalahan sertifikat?
Matya

Jawaban:

67

Karena hanya ada satu ServicePointManager global , pengaturan ServicePointManager.ServerCertificateValidationCallback akan menghasilkan hasil bahwa semua permintaan selanjutnya akan mewarisi kebijakan ini. Karena ini adalah "pengaturan" global, akan lebih disukai untuk mengaturnya dalam metode Application_Start di Global.asax .

Mengatur panggilan balik mengabaikan perilaku default dan Anda sendiri dapat membuat rutin validasi khusus.

Sani Singh Huttunen
sumber
Bagaimana dengan klien yang tidak memiliki Global.asax? Saya memanggil layanan REST yang berjalan di jaringan lokal dari perangkat genggam.
B. Clay Shannon
3
Pertanyaannya khusus untuk HttpWebRequest. Jika Anda menggunakan cara lain, Anda harus melihat dalam dokumentasi cara melakukannya.
Sani Singh Huttunen
Saya menggunakan WebRequest, yang akan dilemparkan ke HttpWebRequest, seperti: ((HttpWebRequest) request) .Accept = contentType;
B. Clay Shannon
Seperti yang dinyatakan dalam jawaban saya: PREFERRED untuk mengaturnya di Global.asax bukan persyaratan. Anda bahkan dapat mengaturnya sebelum panggilan ke layanan REST.
Sani Singh Huttunen
3
Lihat tautan ini untuk solusi yang memungkinkan.
Sani Singh Huttunen
174

Bagi siapa pun yang tertarik menerapkan solusi ini berdasarkan permintaan, ini adalah opsi dan menggunakan ekspresi Lambda. Ekspresi Lambda yang sama dapat diterapkan pada filter global yang disebutkan oleh blak3r juga. Metode ini tampaknya memerlukan .NET 4.5.

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

Di .NET 4.0, Ekspresi Lambda dapat diterapkan ke filter global

ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
Adam Venezia
sumber
2
Apakah ada solusi per-permintaan untuk FtpWebRequest?
Timo
Tampaknya ada baik-baik saja di 4.0
Nacht saya
Saya pikir sejauh ini solusi yang lebih baik untuk varian 'global', walaupun tentu saja saya bisa mengerti mengapa Anda menginginkannya. Secara pribadi saya menyukai pabrik permintaan yang kemudian mengelola panggilan balik validasi ini. Terima kasih Adam, solusi yang bagus.
Senator
2
Mengembalikan trueadalah sesuatu yang dapat Anda lakukan saat bereksperimen selama pengembangan, namun tidak aman. Itu harus bersyarat.
Fred
1
Menggunakan (HttpWebRequest)WebRequest.Create(url)sangat valid, tetapi di kotak saya, HttpWebRequest.Create(url)masih ada dalam penargetan proyek .Net 4.6.2. Pilihan Chef, tetapi pada titik HttpClientini mungkin API yang lebih baik untuk digunakan.
Adam Venezia
53

Ini bekerja untuk saya:

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

Cuplikan dari sini: http://www.west-wind.com/weblog/posts/2011/Feb/11/HttpWebRequest-and-Ignoring-SSL-Certificate-Errors

blak3r
sumber
17
ServicePointManager.ServerCertificateValidationCallback + = (pengirim, sertifikat, rantai, sslPolicyErrors) => true;
David Rutgos
3
Selalu mengembalikan yang benar tidak aman. Seharusnya kondisional mengembalikan true.
Fred
Ini per proses, jadi tidak aman.
Mikhail Orlov
25

Juga ada solusi delegasi singkat:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 
Andrej Rommel
sumber
3
Selalu kembali truetidak aman.
Fred
7
Ya, selalu percaya semua sertifikat SSL tidak aman menurut definisi. Hindari melakukannya jika memungkinkan.
Andrej Rommel
@AndrejRommel apa yang direkomendasikan oleh Anda?
Kiquenet
2
Cara yang disarankan adalah membuat sertifikat SSL yang valid dan menggunakannya dengan benar jika Anda memiliki kendali atas server. Kami akhirnya membuat satu menggunakan letsencrypt.org.
Andrej Rommel
5

Sebutkan bahwa sebelum .NET 4.5 properti pada permintaan untuk mengaksesnya ServicePointManagertidak tersedia.

Berikut adalah .NET 4.0 kode yang akan memberi Anda akses ke ServicePointberdasarkan permintaan per. Itu tidak memberi Anda akses ke panggilan balik per-permintaan, tetapi seharusnya memberi Anda informasi lebih lanjut tentang masalah tersebut. Akses saja scvPoint.Certificate(atau ClientCertificatejika Anda suka) properti.

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());
}
Jesse Chisholm
sumber
Sepakat! Tapi kemudian, OP ini adalah tentang cara ignoremereka, bukan mempercayai mereka.
Jesse Chisholm
Bagaimanapun, Menggunakan ServicePointSaya tidak selalu bisa mempercayai semua sertifikat SSL, juga tidak mengabaikan semua sertifikat , karena belum ServerCertificateValidationCallback mendelegasikan di ServicePoint
Kiquenet
4

Secara kebetulan, ini adalah cara paling tidak resmi untuk mematikan semua validasi sertifikat di aplikasi tertentu yang saya ketahui:

ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
Christian Findlay
sumber
4

Daripada menambahkan panggilan balik ke ServicePointManager yang akan mengesampingkan validasi sertifikat secara global, Anda bisa mengatur panggilan balik pada instance lokal HttpClient. Pendekatan ini hanya akan memengaruhi panggilan yang dibuat menggunakan instance HttpClient itu.

Berikut adalah contoh kode yang menunjukkan bagaimana mengabaikan kesalahan validasi sertifikat untuk server tertentu mungkin diimplementasikan dalam pengontrol 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;
    }

}
Sheldon
sumber
Bukankah ini hanya berfungsi untuk .NET Core? (Atau setiap kali ServerCertificateCustomValidationCallback ditambahkan ke HttpClientHandler)?
phillyslick
Solusi ini harus bekerja di .Net Framework 4.5 dan yang lebih baru serta .Net Core (walaupun saya belum mengujinya dalam .Net Core).
Sheldon
@Sheldon, ini adalah permata :) Digunakan di dalam localhost api-panggilan saya antara .net dan aplikasi inti .net dengan sukses. Penanganan yang bagus tanpa menerima semua.
Besar
3

Berdasarkan jawaban Adam dan komentar Rob, saya menggunakan ini:

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

yang menyaring "pengabaian" agak. Emiten lain dapat ditambahkan seperti yang dipersyaratkan tentunya. Ini diuji dalam. NET 2.0 karena kami perlu mendukung beberapa kode lawas.

Andrej Grobler
sumber
@karank Maaf atas keterlambatan balasan - Dapat ditambahkan di mana saja sebelum panggilan sebenarnya, mis. sebelum memanggil request.GetResponse (). Perhatikan bahwa Penerbit mungkin berisi sesuatu yang lain dalam kasus Anda.
Andrej Grobler
3

CA5386: Alat analisis kerentanan akan memberi tahu Anda tentang kode-kode ini.

Kode yang benar:

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

Untuk .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);
    }
}
Hildebrand yang kaya
sumber
2

Dinyatakan secara eksplisit ...

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;
}
dev_O
sumber
0

Menambah jawaban Sani dan blak3r, saya telah menambahkan kode startup berikut untuk aplikasi saya, tetapi dalam VB:

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

Tampaknya melakukan trik.

MCattle
sumber
0

Tip: Anda juga dapat menggunakan metode ini untuk melacak sertifikat yang akan segera kedaluwarsa. Ini dapat menghemat daging Anda jika Anda menemukan sertifikat yang akan kedaluwarsa dan dapat memperbaikinya tepat waktu. Bagus juga untuk perusahaan pihak ketiga - bagi kami ini adalah DHL / FedEx. DHL membiarkan sertifikat berakhir yang mengacaukan kami 3 hari sebelum Thanksgiving. Untungnya saya ada untuk memperbaikinya ... kali ini!

    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;
            }
        }
    }
Simon_Weaver
sumber
Pastikan untuk menangani situasi di mana mekanisme peringatan Anda dapat memiliki sertifikat kadaluarsa - atau Anda akan berakhir dengan stackoverflow!
Simon_Weaver
Apa ProwlUtil.StepReached?
Kiquenet
Maaf itu hanya metode saya sendiri untuk memanggil API Prowl yang dapat mengirim pemberitahuan ke telepon saya. Namun Anda ingin login itu bagus. Saya suka disadap di ponsel saya untuk hal-hal seperti ini!
Simon_Weaver
0

Beberapa jawaban di atas berhasil. Saya ingin pendekatan yang saya tidak harus terus membuat perubahan kode dan tidak membuat kode saya tidak aman. Karenanya saya membuat daftar putih. Daftar putih dapat dipertahankan di datastore apa pun. Saya menggunakan file konfigurasi karena ini adalah daftar yang sangat kecil.

Kode saya di bawah.

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

Unity C # Versi dari solusi ini:

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;
}
Kekasih Game Santiago
sumber