Insecure SSL
ID |
csharp.insecure_ssl |
Severity |
critical |
Resource |
Misconfiguration |
Language |
CSharp |
Tags |
CWE:295, NIST.SP.800-53, OWASP:2021:A2, OWASP:2021:A7, PCI-DSS:6.5.4 |
Description
Insecure SSL refers to the usage of insecure configurations with SSL/TLS protocols that could compromise data confidentiality, integrity, or authenticity while in transit.
Developers might inadvertently create SSL/TLS connections without enforcing adequate security measures, risking man-in-the-middle (MITM) attacks.
Rationale
The danger of insecure SSL configurations generally stem from mistakes such as using outdated SSL/TLS protocols, disabling certificate validation, or failing to verify hostnames. Code snippets that disable these validations are useful for quick testing. However, leaving them in production can create serious security vulnerabilities.
SSL/TLS security is undermined by:
-
Trusting all certificates, effectively ignoring trust chain verification.
-
Allowing all hostnames to be valid, circumventing checks for URL domain validity and authenticity.
-
Disabling Certificate Revocation List (CRL) or Online Certificate Status Protocol (OCSP) checks for certificate revocation.
-
Using insecure protocols like SSLv3 and TLS 1.0 / 1.1.
The modern HttpClient framework can be configured via System.Net.Http.HttpClientHandler
.
using System;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using static System.Net.Http.HttpClientHandler;
// ...
HttpClientHandler handler = new HttpClientHandler
{
// FLAW: Set up an insecure certificate validation callback
ServerCertificateCustomValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => true,
// or set the accept-any delegate:
ServerCertificateCustomValidationCallback =
DangerousAcceptAnyServerCertificateValidator,
// FLAW: Bypass CRL (Certificate Revocation List) checking
CheckCertificateRevocationList = false,
// FLAW: SSLv3 and TLS 1.0/1.1 are deemed insecure
SslOptions.EnabledSslProtocols =
SslProtocols.Ssl3 | SslProtocols.Tls
| SslProtocols.Tls11 | SslProtocols.Tls12
| SslProtocols.Tls13
};
// Connect to endpoint allowing insecure SSL
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri("https://example.com");
// Use the client...
}
For the (legacy) WebRequest / WebClient framework, System.Net.ServicePointManager
is used to configure SSL/TLS security settings.
Here’s a minimal example that highlights typical insecure coding practices with SSL:
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
// ...
// VULNERABLE: Set up an insecure certificate validation callback
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => true;
// VULNERABLE: Disable CRL checking
ServicePointManager.CheckCertificateRevocationList = false;
// VULNERABLE: SSLv3 and TLS 1.0/1.1 are deemed insecure
ServicePointManager.SecurityProtocol =
SecurityProtocolType.Ssl3
| SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Tls13;
// Connect to endpoint allowing insecure SSL
using (var client = new WebClient())
{
// ... use client to connect to endpoint
}
For low level access to SSL/TLS connections, the System.Net.Security.SslStream
class can be configured.
using System;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
public class UnsafeSslStreamExample
{
public static async Task Main(string[] args)
{
await ConnectWithUnsafeSslStream("example.com", 443);
}
public static async Task ConnectWithUnsafeSslStream(string hostname, int port)
{
// Create TCP connection
using var tcpClient = new TcpClient();
await tcpClient.ConnectAsync(hostname, port);
// VULNERABLE - Create SslStream with unsafe certificate validation
using var sslStream = new SslStream(
tcpClient.GetStream(),
false, // leaveInnerStreamOpen
ValidateServerCertificate // Certificate validation callback - accepts everything
);
try
{
// VULNERABLE - unsafe SSL/TLS protocols and no CRL checking
await sslStream.AuthenticateAsClientAsync(
hostname,
null, // clientCertificates not used
SslProtocols.Default, // Include deprecated protocols
false // checkCertificateRevocation - disabled CRL checking
);
// Fire a simple HTTP request
string httpRequest = $"GET / HTTP/1.1\r\nHost: {hostname}\r\nConnection: close\r\n\r\n";
byte[] requestBytes = Encoding.UTF8.GetBytes(httpRequest);
await sslStream.WriteAsync(requestBytes, 0, requestBytes.Length);
// ... read response
}
catch (AuthenticationException ex)
{
Console.WriteLine($"Authentication failed: {ex.Message}");
}
}
// Unsafe certificate validation - accepts ANY certificate and ANY hostname
private static bool ValidateServerCertificate(
object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
// VULNERABLE: Always return true
// This accepts:
// - Any certificate (valid, invalid, expired, self-signed)
// - Any hostname (bypasses hostname verification)
// - Any certificate chain errors
return true;
}
}
Another unsafe configuration for the ASP.NET Core Kestrel web server follows:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(ConfigureUnsafeKestrel);
});
private static void ConfigureUnsafeKestrel(KestrelServerOptions options)
{
// Configure HTTP endpoint
options.Listen(IPAddress.Any, 8080);
// Configure HTTPS endpoint with maximally unsafe SSL/TLS settings
options.Listen(IPAddress.Any, 8443, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
// Use a self-signed certificate or any certificate
httpsOptions.ServerCertificate = GenerateSelfSignedCertificate();
// VULNERABLE: unsafe SSL protocols, including SSLv3 and TLS 1.0/1.1
httpsOptions.SslProtocols = SslProtocols.Default;
// VULNERABLE: Disable certificate revocation checking
httpsOptions.CheckCertificateRevocation = false;
// enable client certificate validation
httpsOptions.ClientCertificateMode =
ClientCertificateMode.AllowCertificate;
// VULNERABLE: accept *any* client certificate
httpsOptions.ClientCertificateValidation = (certificate, chain, policyErrors) => true;
// alternative to accept *any* client certificate
// httpsOptions.AllowAnyClientCertificate();
});
});
}
These weak configurations undermine security, making it easy for an attacker to intercept or alter communications without being detected.
Remediation
Fixing the insecure HttpClientHandler
configuration goes like this:
// Leave system defaults for SSL/TLS (secure by default in .NET Core 5+)
var handler = new HttpClientHandler()
{
// FIX: Enforce certificate validation
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
sslPolicyErrors == SslPolicyErrors.None,
// FIX: Enable certificate revocation checks
CheckCertificateRevocationList = true
};
For the ServicePointManager
example, the default configuration is generally secure. If you need to weaken it for testing purposes, ensure that the build for production never uses the weakened configuration. The safe default is like this:
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => sslPolicyErrors == SslPolicyErrors.None;
ServicePointManager.CheckCertificateRevocationList = false;
// No need to weaken the default SecurityProtocols allowed;
// but if needed you can force TLS 1.2 or 1.3 only
// (or SecurityProtocolType.SystemDefault)
ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12
#if NET5_0_OR_GREATER
| SecurityProtocolType.Tls13
#endif
;
And finally, for the low-level SslStream
example, fix the insecure configuration like this:
public static async Task ConnectWithSecureSslStream(string hostname, int port)
{
using var tcpClient = new TcpClient();
await tcpClient.ConnectAsync(hostname, port);
// FIX: Secure SslStream with proper certificate validation
using var sslStream = new SslStream(
tcpClient.GetStream(),
leaveInnerStreamOpen: false,
ValidateServerCertificate // reject on any errors
);
try
{
// FIX: Secure SSL/TLS protocols and enable CRL checking
await sslStream.AuthenticateAsClientAsync(
targetHost: hostname,
clientCertificates: null,
enabledSslProtocols: SslProtocols.SystemDefault,
checkCertificateRevocation: true
);
// Use the stream...
}
catch (AuthenticationException ex)
{
Console.WriteLine($"Authentication failed: {ex.Message}");
}
}
// FIX: Secure certificate validation: reject on any errors
private static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return sslPolicyErrors == SslPolicyErrors.None;
}
To remediate issues related to insecure SSL configurations:
-
Use a Trust Store: Always configure the software to use a well-maintained trust store with up-to-date certificates. Avoid using custom trust managers that disable certificate validation.
-
Enforce Hostname Verification: Ensure that hostname verification is enabled so that the TLS clients can match the server’s hostname against its certificate’s naming information.
-
Keep Protocols and Libraries Up-to-date: Regularly update the runtime environment and any third-party libraries to ensure compatibility with the latest secure protocols (e.g., TLS 1.2 or 1.3), avoiding outdated versions like SSLv3.
-
Review Libraries for Vulnerabilities: Regularly audit the libraries and dependencies used in your software projects for known vulnerabilities.
References
-
CWE-295 : Improper Certificate Validation.
-
ServicePointManager configuration (now obsolete).
-
SslStream configuration (low level API).