Tắt dự phòng SSL và chỉ sử dụng TLS cho các kết nối đi trong .NET? (Giảm nhẹ Poodle)


106

Tôi đang cố gắng giảm thiểu lỗ hổng bảo mật của chúng tôi đối với cuộc tấn công Poodle SSL 3.0 Dự phòng . Quản trị viên của chúng tôi đã bắt đầu vô hiệu hóa SSL để hỗ trợ TLS cho các kết nối đến máy chủ của chúng tôi. Và chúng tôi cũng đã khuyên nhóm của mình nên tắt SSL trong trình duyệt web của họ. Bây giờ tôi đang xem xét cơ sở mã .NET của chúng tôi, cơ sở này bắt đầu kết nối HTTPS với các dịch vụ khác nhau thông qua System.Net.HttpWebRequest . Tôi tin rằng các kết nối này có thể dễ bị tấn công MITM nếu chúng cho phép dự phòng từ TLS sang SSL. Đây là những gì tôi đã xác định cho đến nay. Ai đó có thể vui lòng kiểm tra kỹ điều này để xác minh rằng tôi đúng không? Lỗ hổng này là hoàn toàn mới, vì vậy tôi vẫn chưa thấy bất kỳ hướng dẫn nào từ Microsoft về cách giảm thiểu nó trong .NET:

  1. Các giao thức được phép cho lớp System.Net.Security.SslStream, làm nền tảng cho giao tiếp an toàn trong .NET, được đặt toàn cầu cho mỗi AppDomain thông qua thuộc tính System.Net.ServicePointManager.SecurityProtocol .

  2. Giá trị mặc định của thuộc tính này trong .NET 4.5 là Ssl3 | Tls(mặc dù tôi không thể tìm thấy tài liệu để sao lưu điều đó.) SecurityProtocolType là một enum có thuộc tính Flags, vì vậy nó hơi HOẶC trong hai giá trị đó. Bạn có thể kiểm tra điều này trong môi trường của mình bằng dòng mã này:

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

  3. Điều này sẽ được thay đổi thành chỉ Tls, hoặc có thể Tls12, trước khi bạn bắt đầu bất kỳ kết nối nào trong ứng dụng của mình:

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

  4. Quan trọng: Vì thuộc tính hỗ trợ nhiều cờ bitwise, tôi giả sử rằng SslStream sẽ không tự động dự phòng cho các giao thức không xác định khác trong quá trình bắt tay. Nếu không, hỗ trợ nhiều cờ sẽ có ích gì?

Cập nhật về TLS 1.0 so với 1.1 / 1.2:

Theo chuyên gia bảo mật của Google Adam Langley, TLS 1.0 sau đó được phát hiện là có thể bị POODLE tấn công nếu không được triển khai đúng cách , vì vậy bạn nên cân nhắc chuyển sang TLS 1.2 dành riêng.

Cập nhật cho .NET Framework 4.7 trở lên:

Như đã ám chỉ bởi Giáo sư Von Lemongargle bên dưới, bắt đầu từ phiên bản 4.7 của .NET Framework, không cần sử dụng bản hack này vì cài đặt mặc định sẽ cho phép HĐH chọn phiên bản giao thức TLS an toàn nhất. Xem các phương pháp hay nhất về Bảo mật lớp truyền tải (TLS) với .NET Framework để biết thêm thông tin.


1
Về điểm 2 ở trên: xem tham khảoource.microsoft.com/#System/net/System/Net/… SslProtocols "Mặc định = Ssl3 | Tls"
Dai Bok

1
@Dai Bok Mặc định bây giờ là tùy chọn SystemDefault docs.microsoft.com/en-us/dotnet/api/…
MarwaAhmad

@MarwaAhmad nếu đúng như vậy, tham chiếu mã nguồn trong liên kết của tôi không phản ánh mặc định (48 | 192). Nếu được đặt thành không (0), nó sẽ hoàn nguyên về mặc định của hệ thống. Điều này có mùi đối với tôi và tôi có thể sẽ kiểm tra điều này trước khi thực hiện thay đổi vì nó có thể dẫn đến cấu hình sai ... và tắt các giao thức trên khung .net sai ...
Dai Bok

Câu trả lời:


137

Chúng tôi đang làm điều tương tự. Để chỉ hỗ trợ TLS 1.2 và không có giao thức SSL, bạn có thể làm như sau:

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

SecurityProtocolType.Tls chỉ là TLS 1.0, không phải tất cả các phiên bản TLS.

Bên cạnh đó: Nếu bạn muốn kiểm tra xem trang web của mình không cho phép kết nối SSL hay không, bạn có thể thực hiện tại đây (Tôi không nghĩ điều này sẽ bị ảnh hưởng bởi cài đặt trên, chúng tôi đã phải chỉnh sửa sổ đăng ký để buộc IIS sử dụng TLS cho các kết nối đến): https://www.ssllabs.com/ssltest/index.html

Để tắt SSL 2.0 và 3.0 trong IIS, hãy xem trang này: https://www.sslshopper.com/article-how-to-disable-ssl-2.0-in-iis-7.html


Đúng. Ý tưởng hay để hỗ trợ các phiên bản TLS mới hơn: kiểm chứng trong tương lai.
Jordan Rieger

1
Và vì lợi ích của những người khác, chỉnh sửa sổ đăng ký mà bạn đã đề cập cũng có thể được thực hiện bằng các bước sau: serverfault.com/a/637263/98656 . Trong Windows Server 2003 đến 2012 R2, các giao thức được điều khiển bởi các cờ tại HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ SecurityProviders \ Schannel \ Protocols. Để vô hiệu hóa SSLv3, hãy tạo một khóa con tại vị trí trên có tên là 'SSL 3.0' và theo đó, một khóa con có tên 'Máy chủ' và dưới đó, một giá trị DWORD có tên là 'Đã bật', được đặt ở mức 0. Bạn cũng nên tắt SSL 2.0 theo cùng một cách.
Jordan Rieger

4
@ScotterMonkey Bạn chỉ cần đặt System.Net.ServicePointManager.SecurityProtocol nếu bạn đang bắt đầu các kết nối gửi đi từ mã .NET, ví dụ: kết nối với dịch vụ web hoặc API từ mã tùy chỉnh đang chạy trên máy chủ của bạn. Nếu bạn chỉ đang chạy một trang web đơn giản và bạn chỉ chấp nhận các kết nối đến từ các trình duyệt, thì việc sửa chữa sổ đăng ký là đủ.
Jordan Rieger

7
Lưu ý: Nó xuất hiện SecurityProtocolType.Tls11SecurityProtocolType.Tls12các giá trị enum chỉ có sẵn trong ASP.net 4.5 trở lên. Không chắc chúng ta sẽ phải làm gì cho các cơ sở mã cũ hơn chạy trên 2.0 nếu TLS 1.0 đi theo hướng khác.
Sam

1
@AnishV Bạn đặt dòng mã đó trong quá trình khởi chạy ứng dụng của mình, trước bất kỳ mã nào khởi tạo kết nối SSL / TLS đi.
Jordan Rieger

23

Câu trả lời của @Eddie Loeffen dường như là câu trả lời phổ biến nhất cho câu hỏi này, nhưng nó có một số tác động xấu về lâu dài. Nếu bạn xem lại trang tài liệu về System.Net.ServicePointManager.SecurityProtocol thì ở đây phần nhận xét ngụ ý rằng giai đoạn thương lượng chỉ nên giải quyết vấn đề này (và buộc giao thức là hành vi xấu vì trong tương lai, TLS 1.2 cũng sẽ bị xâm phạm). Tuy nhiên, chúng tôi sẽ không tìm kiếm câu trả lời này nếu nó có.

Đang nghiên cứu, có vẻ như giao thức thương lượng ALPN được yêu cầu để truy cập TLS1.2 trong giai đoạn thương lượng. Chúng tôi lấy đó làm điểm xuất phát và thử các phiên bản mới hơn của .Net framework để xem nơi bắt đầu hỗ trợ. Chúng tôi nhận thấy rằng .Net 4.5.2 không hỗ trợ thương lượng với TLS 1.2, nhưng .Net 4.6 thì có.

Vì vậy, mặc dù buộc TLS1.2 sẽ hoàn thành công việc ngay bây giờ, tôi khuyên bạn nên nâng cấp lên .Net 4.6 để thay thế. Vì đây là vấn đề về PCI DSS cho tháng 6 năm 2016, thời hạn ngắn, nhưng khuôn khổ mới là câu trả lời tốt hơn.

CẬP NHẬT: Làm việc từ các nhận xét, tôi đã xây dựng cái này:

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

Để xác thực khái niệm, tôi hoặc kết hợp SSL3 và TLS1.2 và chạy mã nhắm mục tiêu máy chủ chỉ hỗ trợ TLS 1.0 và TLS 1.2 (1.1 bị tắt). Với các giao thức or'd, nó có vẻ kết nối tốt. Nếu tôi thay đổi sang SSL3 và TLS 1.1, điều đó không thể kết nối. Xác thực của tôi sử dụng HttpWebRequest từ System.Net và chỉ gọi GetResponse (). Ví dụ: tôi đã thử điều này và không thành công:

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

trong khi điều này hoạt động:

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

Điều này có một lợi thế so với buộc TLS 1.2 ở chỗ, nếu .Net framework được nâng cấp để có nhiều mục nhập hơn trong Enum, chúng sẽ được hỗ trợ bởi mã như hiện tại. Nó có một bất lợi so với việc chỉ sử dụng .Net 4.6 là 4.6 sử dụng ALPN và sẽ hỗ trợ các giao thức mới nếu không có giới hạn nào được chỉ định.

Chỉnh sửa 29/4/2019 - Microsoft đã xuất bản bài viết này vào tháng 10 năm ngoái. Nó có một bản tóm tắt khá hay về khuyến nghị của họ về cách thực hiện điều này trong các phiên bản khác nhau của khung công tác .net.


3
Hấp dẫn. Có vẻ như trang tài liệu đã được cập nhật cùng với việc chuyển MSDN sang ".NET Framework (phiên bản hiện tại) " và bây giờ giải thích rằng "không có giá trị mặc định nào được liệt kê cho thuộc tính này, có chủ đích". Có lẽ một phiên bản phù hợp hơn trong tương lai của câu trả lời được chấp nhận sẽ là truy vấn thuộc tính trước tiên để truy xuất danh sách các giao thức được phép, sau đó xóa các giao thức mà ứng dụng của bạn cho là không an toàn (tức là bất kỳ thứ gì nhỏ hơn TLS 1.2) thay vì chỉ thêm những cái mà bạn cho là an toàn. Điều này sẽ không loại trừ các phiên bản mới trong tương lai.
Jordan Rieger

Sẽ rất tốt nếu có thể yêu cầu chương trình xóa các giao thức khỏi danh sách mà hệ thống tạo ra, nhưng tôi không thấy cách nào để làm điều đó trong API hiện tại. Lựa chọn duy nhất dường như là buộc giao thức cụ thể, điều mà tôi không hiểu tại sao bất kỳ ai cũng muốn làm. Thật không may, không có hỗ trợ ALPN, đây dường như là cách duy nhất để kết nối TLS1.2 hoạt động.
Giáo sư Von Lemongargle

1
Có thể lặp lại tất cả các enum SecurityProtocolType, xem những cái nào hiện diện trong ServicePointManager.SecurityProtocol cờ enum (nó là hợp lý HOẶC của tất cả các cờ đã đặt, vì vậy bạn có thể kiểm tra từng cờ bằng AND), rồi tạo một cờ mới danh sách chúng với những cái bạn không muốn xóa. Sau đó, kết hợp chúng thành một enum và đặt thuộc tính cho nó.
Jordan Rieger

Tôi vừa đọc lại mã enum / looping của bạn và tôi nghĩ nó không chính xác. Toán tử logic | = sẽ dẫn đến thuộc tính bao gồm bất kỳ giá trị mặc định nào được đặt trong thuộc tính ban đầu, thay vì chỉ bao gồm Tls12 trở lên. Để khắc phục, bạn phải khởi tạo biến enum SecurityProtocolType với giá trị 0, thực hiện vòng lặp | = đối với biến đó, rồi gán nó cho thuộc tính ServicePointManager.SecurityProtocol sau đó.
Jordan Rieger

7
Có ai khác thấy điên rồ khi .NET không tự động thương lượng phiên bản giao thức cao nhất mà nó có khả năng ?!
Raman

5

@watson

Trên các biểu mẫu cửa sổ, nó có sẵn, ở đầu lớp đặt

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

vì cửa sổ là một luồng, nên tất cả những gì bạn cần, trong trường hợp nó là một dịch vụ, bạn cần đặt nó ngay trên lệnh gọi đến dịch vụ (vì không có thông báo bạn sẽ ở trên luồng nào).

using System.Security.Principal 

cũng cần thiết.


5

Nếu bạn tò mò về những giao thức .NET hỗ trợ, bạn có thể thử HttpClient trên 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");

Kết quả là chết tiệt:

Máy khách của bạn đang sử dụng TLS 1.0, đã rất cũ, có thể dễ bị tấn công BEAST và không có sẵn bộ mật mã tốt nhất. Các bổ sung như AES-GCM và SHA256 để thay thế MD5-SHA-1 không có sẵn cho máy khách TLS 1.0 cũng như nhiều bộ mật mã hiện đại hơn.

Như Eddie giải thích ở trên, bạn có thể kích hoạt các giao thức tốt hơn theo cách thủ công:

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

Tôi không biết tại sao nó lại sử dụng các giao thức không hợp lệ. Đó có vẻ là một lựa chọn thiết lập kém, tương đương với một lỗi bảo mật lớn (tôi cá là nhiều ứng dụng không thay đổi mặc định). Làm thế nào chúng tôi có thể báo cáo nó?


5

Tôi đã phải ép kiểu số nguyên tương đương để tránh thực tế là tôi vẫn đang sử dụng .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,
   } 
*/

Điều này hoạt động nhưng .NET 4.0 không hỗ trợ TLS 1.2, tuy nhiên .NET 4.5 trở lên hỗ trợ TLS 1.2. Vì vậy, bạn có thể thêm mã này (hoặc thêm làm một chút HOẶC để thêm hỗ trợ cho thương lượng TLS 1.2) vào ứng dụng .NET 4.0 của mình và xây dựng nó nhưng bạn sẽ cần triển khai mã trên .NET 4.5 trở lên. blogs.perficiency.com/microsoft/2016/04/tsl-1-2-and-net-support
rboy

Cũng thấy điều này, .NET 4.0 mã sẽ hoạt động tốt trên phiên bản cao hơn của .NET bao gồm cả .NET 4.5 và .NET 4.6 stackoverflow.com/questions/33378902/...
rboy

Truyền số nguyên hoạt động để gửi TLS 1.2. Giá trị enum Tls12 chỉ không tồn tại trong NET 4.0.
CZahrobsky

Hai điểm khác nhau. Xem bình luận của tôi. Bạn có thể đặt giá trị nhưng nếu phiên bản Net thời gian chạy của bạn là 4.0 thì nó sẽ không thành công. Bạn có thể biên dịch với cờ này nhưng phiên bản .NET runtime của bạn cần phải được 4.5 hoặc cao hơn như các thành phần dựa trên .NET 4.0 không hỗ trợ thuật toán mã hóa cần thiết cho TLS 1.2 (xem các liên kết)
rboy

2
Có một số hotfix cho các phiên bản thời gian chạy .NET cũ hơn để thêm hỗ trợ TLS 1.2. Ví dụ: support.microsoft.com/en-us/help/3154518/… , CZahrobsky cũng có thể đã sử dụng tính năng này trên bản cập nhật Win10 Fall dành cho người tạo cũng bao gồm hotfix.
giai điệu im lặng

1

Tôi thấy giải pháp đơn giản nhất là thêm hai mục đăng ký như sau (chạy điều này trong dấu nhắc lệnh với đặc quyền quản trị):

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

Những mục này dường như ảnh hưởng đến cách .NET CLR chọn giao thức khi tạo kết nối an toàn với tư cách là máy khách.

Có thêm thông tin về mục đăng ký này ở đây:

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

Điều này không chỉ đơn giản hơn, mà giả sử nó hoạt động cho trường hợp của bạn, mạnh mẽ hơn nhiều so với một giải pháp dựa trên mã, yêu cầu các nhà phát triển theo dõi giao thức và sự phát triển và cập nhật tất cả mã liên quan của họ. Hy vọng rằng các thay đổi môi trường tương tự có thể được thực hiện cho TLS 1.3 và hơn thế nữa, miễn là .NET vẫn đủ ngu ngốc để không tự động chọn giao thức cao nhất hiện có.

LƯU Ý : Mặc dù theo bài viết trên, điều này chỉ được cho là vô hiệu hóa RC4 và người ta sẽ không nghĩ rằng điều này sẽ thay đổi liệu máy khách .NET có được phép sử dụng TLS1.2 + hay không, vì một số lý do nó có điều này hiệu ứng.

LƯU Ý : Như đã lưu ý bởi @Jordan Rieger trong phần nhận xét, đây không phải là giải pháp cho POODLE, vì nó không vô hiệu hóa các giao thức cũ hơn a - nó chỉ cho phép máy khách làm việc với các giao thức mới hơn, ví dụ khi máy chủ được vá đã vô hiệu hóa cũ hơn các giao thức. Tuy nhiên, với một cuộc tấn công MITM, rõ ràng một máy chủ bị xâm nhập sẽ cung cấp cho máy khách một giao thức cũ hơn, sau đó máy khách sẽ vui vẻ sử dụng.

VIỆC CẦN LÀM : Cố gắng tắt sử dụng phía máy khách của TLS1.0 và TLS1.1 với các mục đăng ký này, tuy nhiên, tôi không biết liệu các thư viện máy khách .NET http có tôn trọng các cài đặt này hay không:

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


Cài đặt đăng ký thay thế cho mã sẽ rất tuyệt, nhưng những cài đặt này có thực sự vô hiệu hóa TLS 1.0 và 1.1 để chỉ cho phép các kết nối máy khách sử dụng TLS 1.2 trở lên không? Theo liên kết, nó dường như chỉ vô hiệu hóa RC4 trong TLS. Tôi nghĩ rằng cuộc tấn công của Poodle rộng hơn thế.
Jordan Rieger

@JordanRieger Các mục đăng ký này cho phép máy khách .NET kết nối với máy chủ đã tắt các giao thức cũ hơn để giảm POODLE. Nếu không có những thứ này, máy khách sẽ gặp lỗi vì máy khách .NET khăng khăng sử dụng giao thức cũ hơn ngay cả khi máy chủ yêu cầu một giao thức mới hơn. Tất cả các cược sẽ tắt nếu máy chủ của bạn vẫn cho phép kết nối bằng các giao thức cũ hơn. Về mặt lý thuyết, các giao thức cũ hơn nên bị vô hiệu hóa. Tôi tự hỏi liệu các mục đăng ký tương tự cho phép tắt các mục này trên máy chủ (ví dụ: nartac.com/Products/IISCrypto ) có hoạt động cho máy khách không?
Raman

Trong các mục đăng ký mà nartac thao tác, có các cài đặt riêng biệt cho (khi hoạt động như) máy khách và (khi hoạt động như) máy chủ. Tuy nhiên, tôi không nhớ liệu giao diện của chúng có phân biệt hay không. Bạn có biết những phiên bản nào của .net hỗ trợ hack đăng ký này không?
Giáo sư Von Lemongargle

Tuy nhiên, @Raman điểm của câu hỏi của tôi là giảm thiểu lỗ hổng POODLE khi máy khách của bạn đang kết nối với máy chủ mà bạn không kiểm soát. Lỗ hổng sẽ cho phép kẻ tấn công MITM hạ cấp giao thức xuống phiên bản TLS hoặc SSL cũ hơn có thể bị tấn công. Chỉ vô hiệu hóa RC4 là không đủ. Các cài đặt đăng ký này có thể hữu ích cho một số trường hợp nhất định, nhưng không phải trường hợp trong câu hỏi của tôi.
Jordan Rieger

1
@JordanRieger Đồng ý. Tôi đã cập nhật văn bản với một số quan sát và suy nghĩ bổ sung.
Raman
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.