Nonaktifkan SSL fallback dan gunakan hanya TLS untuk koneksi keluar di .NET? (Mitigasi pudel)

106

Saya mencoba mengurangi kerentanan kami terhadap serangan Poodle SSL 3.0 Fallback . Admin kami telah mulai menonaktifkan SSL untuk mendukung TLS untuk koneksi masuk ke server kami. Dan kami juga menyarankan tim kami untuk menonaktifkan SSL di browser web mereka. Saya sekarang melihat basis kode .NET kami, yang memulai koneksi HTTPS dengan berbagai layanan melalui System.Net.HttpWebRequest . Saya yakin bahwa koneksi ini dapat rentan terhadap serangan MITM jika memungkinkan fallback dari TLS ke SSL. Inilah yang telah saya tentukan sejauh ini. Bisakah seseorang memeriksa ulang ini untuk memverifikasi bahwa saya benar? Kerentanan ini masih baru, jadi saya belum melihat panduan apa pun dari Microsoft tentang cara menguranginya di .NET:

  1. Protokol yang diizinkan untuk kelas System.Net.Security.SslStream, yang menopang komunikasi aman di .NET, disetel secara global untuk setiap AppDomain melalui properti System.Net.ServicePointManager.SecurityProtocol .

  2. Nilai default dari properti ini di .NET 4.5 adalah Ssl3 | Tls(walaupun saya tidak dapat menemukan dokumentasi untuk mendukungnya.) SecurityProtocolType adalah enum dengan atribut Flags, jadi itu sedikit OR dari dua nilai tersebut. Anda dapat memeriksanya di lingkungan Anda dengan baris kode ini:

    Console.WriteLine (System.Net.ServicePointManager.SecurityProtocol.ToString ());

  3. Ini harus diubah menjadi hanya Tls, atau mungkin Tls12, sebelum Anda memulai koneksi apa pun di aplikasi Anda:

    System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls;

  4. Penting: Karena properti mendukung beberapa bendera bitwise, saya berasumsi bahwa SslStream tidak akan otomatis mundur ke protokol tidak ditentukan lainnya selama jabat tangan. Jika tidak, apa gunanya mendukung banyak bendera?

Pembaruan pada TLS 1.0 vs 1.1 / 1.2:

Menurut pakar keamanan Google Adam Langley, TLS 1.0 kemudian ditemukan rentan terhadap POODLE jika tidak diterapkan dengan benar , jadi Anda harus mempertimbangkan untuk pindah ke TLS 1.2 secara eksklusif.

Pembaruan untuk .NET Framework 4.7 dan yang lebih baru:

Seperti disinggung oleh Prof Von Lemongargle di bawah ini, dimulai dengan versi 4.7 dari .NET Framework, tidak perlu menggunakan peretasan ini karena pengaturan default akan memungkinkan OS untuk memilih versi protokol TLS yang paling aman. Lihat praktik terbaik Transport Layer Security (TLS) dengan .NET Framework untuk informasi selengkapnya.

Jordan Rieger
sumber
1
Mengenai poin 2 di atas: lihat referensiource.microsoft.com/#System/net/System/Net/… SslProtocols "Default = Ssl3 | Tls"
Dai Bok
1
@Dai Bok Defaultnya sekarang adalah opsi SystemDefault docs.microsoft.com/en-us/dotnet/api/…
MarwaAhmad
@MarwaAhmad jika demikian, referensi kode sumber di tautan saya tidak mencerminkan default (48 | 192). Jika disetel ke tidak ada (0), ini harus kembali ke default sistem. Ini berbau bagi saya dan saya mungkin akan mengujinya sebelum membuat perubahan karena dapat menyebabkan kesalahan konfigurasi ... dan mematikan protokol pada kerangka .net yang salah ...
Dai Bok

Jawaban:

137

Kami melakukan hal yang sama. Untuk hanya mendukung TLS 1.2 dan tanpa protokol SSL, Anda dapat melakukan ini:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

SecurityProtocolType.Tls hanya TLS 1.0, tidak semua versi TLS.

Sebagai tambahan: Jika Anda ingin memeriksa bahwa situs Anda tidak mengizinkan koneksi SSL, Anda dapat melakukannya di sini (menurut saya ini tidak akan terpengaruh oleh pengaturan di atas, kami harus mengedit registri untuk memaksa IIS menggunakan TLS untuk koneksi masuk): https://www.ssllabs.com/ssltest/index.html

Untuk menonaktifkan SSL 2.0 dan 3.0 di IIS, lihat halaman ini: https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html

Eddie Fletcher
sumber
Baik. Ide bagus untuk mendukung versi TLS yang lebih baru juga: pemeriksaan masa depan.
Jordan Rieger
1
Dan untuk kepentingan orang lain, pengeditan registri yang Anda sebutkan juga dapat dilakukan dengan langkah-langkah berikut: serverfault.com/a/637263/98656 . Di Windows Server 2003 hingga 2012 R2, protokol dikontrol oleh bendera di HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ Schannel \ Protocols. Untuk menonaktifkan SSLv3, buat subkunci di lokasi di atas bernama 'SSL 3.0' dan, di bawahnya, subkunci bernama 'Server' dan, di bawah sana, nilai DWORD bernama 'Enabled', ditetapkan ke 0. Anda juga harus menonaktifkan SSL 2.0 di jalan yang sama.
Jordan Rieger
4
@ScotterMonkey Anda hanya perlu menyetel System.Net.ServicePointManager.SecurityProtocol jika Anda memulai koneksi keluar dari kode .NET, misalnya menghubungkan ke layanan web atau API dari kode khusus yang berjalan di server Anda. Jika Anda hanya menjalankan situs web sederhana, dan Anda hanya menerima koneksi masuk dari browser, maka perbaikan registri sudah cukup.
Jordan Rieger
7
Catatan: Muncul SecurityProtocolType.Tls11dan SecurityProtocolType.Tls12nilai enum hanya tersedia di ASP.net 4.5 dan yang lebih baru. Tidak yakin apa yang harus kami lakukan untuk basis kode lama yang berjalan pada 2.0 jika TLS 1.0 melewati batas.
Sam
1
@AnishV Anda menempatkan baris kode tersebut dalam inisialisasi aplikasi Anda, sebelum kode apa pun yang memulai koneksi SSL / TLS keluar.
Jordan Rieger
23

Jawaban @Eddie Loeffen tampaknya menjadi jawaban paling populer untuk pertanyaan ini, tetapi memiliki beberapa efek jangka panjang yang buruk. Jika Anda meninjau halaman dokumentasi untuk System.Net.ServicePointManager.SecurityProtocol di sini , bagian komentar menyiratkan bahwa fase negosiasi seharusnya hanya membahas ini (dan memaksa protokol adalah praktik yang buruk karena di masa mendatang, TLS 1.2 akan dikompromikan juga). Namun, kami tidak akan mencari jawaban ini jika ya.

Meneliti, ternyata protokol negosiasi ALPN diperlukan untuk sampai ke TLS1.2 dalam fase negosiasi. Kami menganggapnya sebagai titik awal dan mencoba versi yang lebih baru dari kerangka .Net untuk melihat di mana dukungan dimulai. Kami menemukan bahwa .Net 4.5.2 tidak mendukung negosiasi ke TLS 1.2, tetapi .Net 4.6 mendukung.

Jadi, meskipun memaksa TLS1.2 akan menyelesaikan pekerjaan sekarang, saya sarankan Anda meningkatkan ke .Net 4.6 sebagai gantinya. Karena ini adalah masalah PCI DSS untuk Juni 2016, jendelanya pendek, tetapi kerangka kerja baru adalah jawaban yang lebih baik.

UPDATE: Bekerja dari komentar, saya membuat ini:

ServicePointManager.SecurityProtocol = 0;    
foreach (SecurityProtocolType protocol in SecurityProtocolType.GetValues(typeof(SecurityProtocolType)))
    {
        switch (protocol)
        {
            case SecurityProtocolType.Ssl3:
            case SecurityProtocolType.Tls:
            case SecurityProtocolType.Tls11:
                break;
            default:
                ServicePointManager.SecurityProtocol |= protocol;
            break;
        }
    }

Untuk memvalidasi konsep, saya atau bersama-sama dengan SSL3 dan TLS1.2 dan menjalankan kode yang menargetkan server yang hanya mendukung TLS 1.0 dan TLS 1.2 (1.1 dinonaktifkan). Dengan protokol or'd, tampaknya terhubung dengan baik. Jika saya mengubah ke SSL3 dan TLS 1.1, itu gagal terhubung. Validasi saya menggunakan HttpWebRequest dari System.Net dan hanya memanggil GetResponse (). Misalnya, saya mencoba ini dan gagal:

        HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls11;
        request.GetResponse();

sementara ini berhasil:

        HttpWebRequest request = WebRequest.Create("https://www.contoso.com/my/web/resource") as HttpWebRequest;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
        request.GetResponse();

Ini memiliki keunggulan dibandingkan memaksa TLS 1.2 karena, jika kerangka kerja .Net ditingkatkan sehingga ada lebih banyak entri di Enum, mereka akan didukung oleh kode sebagaimana adanya. Ini memiliki kelemahan daripada hanya menggunakan .Net 4.6 di 4.6 menggunakan ALPN dan harus mendukung protokol baru jika tidak ada batasan yang ditentukan.

Sunting 29/4/2019 - Microsoft menerbitkan artikel ini Oktober lalu. Ini memiliki sinopsis yang cukup bagus dari rekomendasi mereka tentang bagaimana hal ini harus dilakukan dalam berbagai versi kerangka kerja .net.

Prof Von Lemongargle
sumber
3
Menarik. Sepertinya halaman dokumentasi telah diperbarui bersama dengan MSDN pindah ke ".NET Framework (versi saat ini) " dan sekarang menjelaskan bahwa "tidak ada nilai default yang dicantumkan untuk properti ini, dengan sengaja." Mungkin versi yang lebih tahan terhadap masa depan dari jawaban yang diterima adalah dengan menanyakan properti terlebih dahulu untuk mengambil daftar protokol yang diizinkan, dan kemudian menghapus yang dianggap tidak aman oleh aplikasi Anda (yaitu apa pun yang kurang dari TLS 1.2) daripada secara eksplisit menambahkan hanya yang Anda anggap aman. Ini tidak akan mengecualikan versi baru di masa mendatang.
Jordan Rieger
Akan lebih baik jika program dapat menghapus protokol dari daftar yang dibuat oleh sistem, tetapi saya tidak melihat cara untuk melakukannya di API saat ini. Satu-satunya pilihan tampaknya adalah memaksakan protokol tertentu, yang saya tidak mengerti mengapa ada orang yang ingin melakukannya. Sayangnya, tanpa dukungan ALPN, tampaknya ini satu-satunya cara agar koneksi TLS1.2 berfungsi.
Prof Von Lemongargle
1
Seharusnya dimungkinkan untuk mengulang melalui semua enum SecurityProtocolType, melihat mana yang ada di enum flag ServicePointManager.SecurityProtocol (ini adalah OR logis dari semua flag yang ditetapkan, sehingga Anda dapat menguji masing-masing dengan AND), lalu membuat yang baru daftar mereka dengan yang tidak ingin Anda hapus. Kemudian gabungkan keduanya menjadi satu enum dan setel properti dengan itu.
Jordan Rieger
Saya baru saja membaca ulang enum / kode perulangan Anda, dan menurut saya itu salah. Operator logika | = akan menghasilkan properti yang menyertakan nilai default apa pun yang awalnya disetel di properti, daripada hanya menyertakan Tls12 ke atas. Untuk memperbaikinya, Anda harus menginisialisasi variabel enum SecurityProtocolType dengan nilai 0, melakukan pengulangan | = terhadap variabel tersebut, dan kemudian menetapkannya ke properti ServicePointManager.SecurityProtocol sesudahnya.
Jordan Rieger
7
Apakah orang lain menganggapnya gila bahwa .NET tidak secara otomatis menegosiasikan versi protokol tertinggi yang mampu dilakukannya ?!
Raman
5

@tokopedia

Pada bentuk jendela tersedia, di bagian atas put kelas

  static void Main(string[] args)
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
       //other stuff here
    }

karena windows adalah single threaded, itu semua yang Anda butuhkan, jika itu adalah layanan yang Anda butuhkan untuk meletakkannya tepat di atas panggilan ke layanan (karena tidak ada yang tahu utas apa yang akan Anda gunakan).

using System.Security.Principal 

juga dibutuhkan.

DirtyHowi
sumber
5

Jika Anda penasaran dengan protokol mana yang didukung .NET, Anda dapat mencoba HttpClient di https://www.howsmyssl.com/

// set proxy if you need to
// WebRequest.DefaultWebProxy = new WebProxy("http://localhost:3128");

File.WriteAllText("howsmyssl-httpclient.html", new HttpClient().GetStringAsync("https://www.howsmyssl.com").Result);

// alternative using WebClient for older framework versions
// new WebClient().DownloadFile("https://www.howsmyssl.com/", "howsmyssl-webclient.html");

Hasilnya memberatkan:

Klien Anda menggunakan TLS 1.0, yang sangat tua, mungkin rentan terhadap serangan BEAST, dan tidak memiliki cipher suite terbaik yang tersedia di dalamnya. Penambahan seperti AES-GCM, dan SHA256 untuk menggantikan MD5-SHA-1 tidak tersedia untuk klien TLS 1.0 serta banyak cipher suite modern lainnya.

Seperti yang dijelaskan Eddie di atas, Anda dapat mengaktifkan protokol yang lebih baik secara manual:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11; 

Saya tidak tahu mengapa itu menggunakan protokol yang buruk di luar kotak. Tampaknya pilihan pengaturan yang buruk, sama saja dengan bug keamanan utama (saya yakin banyak aplikasi tidak mengubah default). Bagaimana kami dapat melaporkannya?

Kolonel Panik
sumber
5

Saya harus memasukkan bilangan bulat yang setara untuk menyiasati fakta bahwa saya masih menggunakan .NET 4.0

System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
/* Note the property type  
   [System.Flags]
   public enum SecurityProtocolType
   {
     Ssl3 = 48,
     Tls = 192,
     Tls11 = 768,
     Tls12 = 3072,
   } 
*/
CZahrobsky
sumber
Ini berfungsi tetapi .NET 4.0 tidak mendukung TLS 1.2, namun .NET 4.5 dan lebih tinggi mendukung TLS 1.2. Jadi Anda dapat menambahkan kode ini (atau menambahkan lakukan bitwise ATAU untuk menambahkan dukungan untuk negosiasi TLS 1.2) ke aplikasi .NET 4.0 Anda dan membangunnya tetapi Anda perlu menerapkan kode pada .NET 4.5 atau lebih tinggi. blogs.perficient.com/microsoft/2016/04/tsl-1-2-and-net-support
rboy
Lihat juga ini, kode .NET 4.0 akan berfungsi dengan baik pada versi .NET yang lebih tinggi termasuk .NET 4.5 dan .NET 4.6 stackoverflow.com/questions/33378902/…
rboy
Pemeran integer bekerja untuk mengirim TLS 1.2. Nilai enum Tls12 tidak ada di. NET 4.0
CZahrobsky
Dua poin berbeda. Lihat komentar saya. Anda dapat memberikan nilai tetapi jika runtime Anda versi Net 4.0 itu akan gagal. Anda dapat mengompilasi dengan flag ini tetapi runtime versi .NET Anda harus 4.5 atau lebih tinggi karena komponen dasar pada .NET 4.0 tidak mendukung cipher yang diperlukan untuk TLS 1.2 (lihat
tautannya
2
Ada beberapa perbaikan terbaru untuk versi runtime .NET lebih lama untuk menambahkan dukungan TLS 1.2. misalnya support.microsoft.com/en-us/help/3154518/… , CZahrobsky mungkin juga telah menggunakan ini pada pembaruan pembuat musim gugur Win10 yang juga termasuk perbaikan terbaru.
nada hening
1

Saya menemukan solusi paling sederhana adalah menambahkan dua entri registri sebagai berikut (jalankan ini di prompt perintah dengan hak istimewa admin):

reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:32

reg add HKLM\SOFTWARE\Microsoft\.NETFramework\v4.0.30319 /v SchUseStrongCrypto /t REG_DWORD /d 1 /reg:64

Entri ini tampaknya mempengaruhi bagaimana .NET CLR memilih protokol saat membuat sambungan aman sebagai klien.

Ada informasi lebih lanjut tentang entri registri ini di sini:

https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2015/2960358#suggested-actions

Ini tidak hanya lebih sederhana, tetapi dengan asumsi itu berfungsi untuk kasus Anda, jauh lebih kuat daripada solusi berbasis kode, yang mengharuskan pengembang untuk melacak protokol dan pengembangan dan memperbarui semua kode yang relevan. Mudah-mudahan, perubahan lingkungan serupa dapat dibuat untuk TLS 1.3 dan seterusnya, selama .NET tetap cukup bodoh untuk tidak secara otomatis memilih protokol tertinggi yang tersedia.

CATATAN : Meskipun, menurut artikel di atas, ini hanya untuk menonaktifkan RC4, dan orang tidak akan berpikir ini akan mengubah apakah klien .NET diizinkan untuk menggunakan TLS1.2 + atau tidak, untuk beberapa alasan memang memiliki ini efek.

CATATAN : Seperti dicatat oleh @Jordan Rieger di komentar, ini bukan solusi untuk POODLE, karena tidak menonaktifkan protokol yang lebih lama a - ini hanya memungkinkan klien untuk bekerja dengan protokol yang lebih baru misalnya ketika server yang ditambal telah menonaktifkan yang lebih lama protokol. Namun, dengan serangan MITM, jelas server yang dikompromikan akan menawarkan klien protokol yang lebih lama, yang kemudian akan digunakan dengan senang hati oleh klien.

TODO : Coba nonaktifkan penggunaan sisi klien TLS1.0 dan TLS1.1 dengan entri registri ini, namun saya tidak tahu apakah pustaka klien .NET http menghormati pengaturan ini atau tidak:

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-10

https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings#tls-11

Raman
sumber
Pengaturan registri sebagai alternatif kode akan sangat bagus, tetapi apakah pengaturan ini benar-benar menonaktifkan TLS 1.0 dan 1.1 demi hanya mengizinkan koneksi klien menggunakan TLS 1.2 dan yang lebih baru? Menurut tautan tersebut, tampaknya hanya menonaktifkan RC4 di TLS. Saya pikir serangan Poodle lebih luas dari itu.
Jordan Rieger
@JordanRieger Entri registri ini memungkinkan klien .NET untuk menyambung ke server yang memiliki protokol lama dinonaktifkan untuk mengurangi POODLE. Tanpa ini, klien akan membuat kesalahan karena klien .NET dengan bodohnya bersikeras menggunakan protokol yang lebih lama bahkan ketika server meminta yang lebih baru. Semua taruhan dibatalkan jika server Anda masih mengizinkan koneksi menggunakan protokol yang lebih lama. Secara teoritis protokol lama harus dinonaktifkan. Saya ingin tahu apakah entri registri yang sama yang memungkinkan penonaktifan ini di server (misalnya nartac.com/Products/IISCrypto ) juga akan berfungsi untuk klien?
Raman
Dalam entri registri yang dimanipulasi oleh nartac, terdapat pengaturan terpisah untuk (saat bertindak sebagai) klien dan (saat bertindak sebagai) server. Saya tidak ingat apakah antarmuka mereka berbeda. Tahukah Anda versi .net apa yang mendukung peretasan registri ini?
Prof Von Lemongargle
@ Raman, inti dari pertanyaan saya, adalah untuk mengurangi kerentanan POODLE ketika klien Anda terhubung ke server yang tidak Anda kontrol. Kerentanan tersebut akan memungkinkan penyerang MITM menurunkan versi protokol ke versi TLS atau SSL yang lebih lama yang dapat diretas. Menonaktifkan RC4 saja tidak cukup. Pengaturan registri ini mungkin berguna untuk kasus tertentu, tetapi bukan skenario dalam pertanyaan saya.
Jordan Rieger
1
@ JordanRieger Setuju. Saya memperbarui teks dengan beberapa pengamatan dan pemikiran tambahan.
Raman