Now that SSL 3 has been found to be vulnerable to the POODLE attack:
Which versions of SSL/TLS does System.Net.WebRequest use when connecting to any https Uri?
I use WebRequest to connect to several 3rd party API's. One of these has now said they will block any request that uses SSL 3. But WebRequest is part of the .Net core framework (using 4.5) so it is not obvious what version it uses.
This is an important question. The SSL 3 protocol (1996) is irreparably broken by the Poodle attack published 2014. The IETF have published "SSLv3 MUST NOT be used". Web browsers are ditching it. Mozilla Firefox and Google Chrome have already done so.
Two excellent tools for checking protocol support in browsers are SSL Lab's client test and https://www.howsmyssl.com/ . The latter does not require Javascript, so you can try it from .NET's HttpClient:
// 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");
The result is damning:
Your client is using TLS 1.0, which is very old, possibly susceptible to the BEAST attack, and doesn't have the best cipher suites available on it. Additions like AES-GCM, and SHA256 to replace MD5-SHA-1 are unavailable to a TLS 1.0 client as well as many more modern cipher suites.
That's concerning. It's comparable to 2006's Internet Explorer 7.
To list exactly which protocols a HTTP client supports, you can try the version-specific test servers below:
var test_servers = new Dictionary<string, string>();
test_servers["SSL 2"] = "https://www.ssllabs.com:10200";
test_servers["SSL 3"] = "https://www.ssllabs.com:10300";
test_servers["TLS 1.0"] = "https://www.ssllabs.com:10301";
test_servers["TLS 1.1"] = "https://www.ssllabs.com:10302";
test_servers["TLS 1.2"] = "https://www.ssllabs.com:10303";
var supported = new Func<string, bool>(url =>
{
try { return new HttpClient().GetAsync(url).Result.IsSuccessStatusCode; }
catch { return false; }
});
var supported_protocols = test_servers.Where(server => supported(server.Value));
Console.WriteLine(string.Join(", ", supported_protocols.Select(x => x.Key)));
I'm using .NET Framework 4.6.2. I found HttpClient supports only SSL 3 and TLS 1.0. That's concerning. This is comparable to 2006's Internet Explorer 7.
Update: It turns HttpClient does support TLS 1.1 and 1.2, but you have to turn them on manually at System.Net.ServicePointManager.SecurityProtocol
. See https://stackoverflow.com/a/26392698/284795
I don't know why it uses bad protocols out-the-box. That seems a poor setup choice, tantamount to a major security bug (I bet plenty of applications don't change the default). How can we report it?
When using System.Net.WebRequest your application will negotiate with the server to determine the highest TLS version that both your application and the server support, and use this. You can see more details on how this works here:
http://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_handshake
If the server doesn't support TLS it will fallback to SSL, therefore it could potentially fallback to SSL3. You can see all of the versions that .NET 4.5 supports here:
http://msdn.microsoft.com/en-us/library/system.security.authentication.sslprotocols(v=vs.110).aspx
In order to prevent your application being vulnerable to POODLE, you can disable SSL3 on the machine that your application is running on by following this explanation:
SecurityProtocolType.Tls
(and therefore TLS 1.0) in .net framework 3.5 or lower
TLS
was something that would actually be implemented at the OS/machine level? Isn't that where the actual HTTP traffic is occuring? So I don't think it makes sense to try to tell your code to use a particular TLS that's really determined by the OS.
I also put an answer there, but the article @Colonel Panic's update refers to suggests forcing TLS 1.2. In the future, when TLS 1.2 is compromised or just superceded, having your code stuck to TLS 1.2 will be considered a deficiency. Negotiation to TLS1.2 is enabled in .Net 4.6 by default. If you have the option to upgrade your source to .Net 4.6, I would highly recommend that change over forcing TLS 1.2.
If you do force TLS 1.2, strongly consider leaving some type of breadcrumb that will remove that force if you do upgrade to the 4.6 or higher framework.
Success story sharing