Unsafe certificate trust¶
ID: java/unsafe-cert-trust
Kind: problem
Security severity: 9.8
Severity: warning
Precision: medium
Tags:
- security
- external/cwe/cwe-273
Query suites:
- java-security-extended.qls
- java-security-and-quality.qls
Click to see the query in the CodeQL repository
Java offers two mechanisms for SSL authentication - trust manager and hostname verifier (the later is checked by the java/insecure-hostname-verifier
query). The trust manager validates the peer’s certificate chain while hostname verification establishes that the hostname in the URL matches the hostname in the server’s identification.
When SSLSocket
or SSLEngine
are created without a secure setEndpointIdentificationAlgorithm
, hostname verification is disabled by default.
This query checks whether setEndpointIdentificationAlgorithm
is missing, thereby making the application vulnerable to man-in-the-middle attacks. The query also covers insecure configurations of com.rabbitmq.client.ConnectionFactory
.
Recommendation¶
Validate SSL certificates in SSL authentication.
Example¶
The following two examples show two ways of configuring SSLSocket/SSLEngine. In the ‘BAD’ case, setEndpointIdentificationAlgorithm
is not called, thus no hostname verification takes place. In the ‘GOOD’ case, setEndpointIdentificationAlgorithm
is called.
public static void main(String[] args) {
{
SSLContext sslContext = SSLContext.getInstance("TLS");
SSLEngine sslEngine = sslContext.createSSLEngine();
SSLParameters sslParameters = sslEngine.getSSLParameters();
sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); //GOOD: Set a valid endpointIdentificationAlgorithm for SSL engine to trigger hostname verification
sslEngine.setSSLParameters(sslParameters);
}
{
SSLContext sslContext = SSLContext.getInstance("TLS");
SSLEngine sslEngine = sslContext.createSSLEngine(); //BAD: No endpointIdentificationAlgorithm set
}
{
SSLContext sslContext = SSLContext.getInstance("TLS");
final SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443);
SSLParameters sslParameters = sslEngine.getSSLParameters();
sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); //GOOD: Set a valid endpointIdentificationAlgorithm for SSL socket to trigger hostname verification
socket.setSSLParameters(sslParameters);
}
{
com.rabbitmq.client.ConnectionFactory connectionFactory = new com.rabbitmq.client.ConnectionFactory();
connectionFactory.useSslProtocol();
connectionFactory.enableHostnameVerification(); //GOOD: Enable hostname verification for rabbitmq ConnectionFactory
}
{
com.rabbitmq.client.ConnectionFactory connectionFactory = new com.rabbitmq.client.ConnectionFactory();
connectionFactory.useSslProtocol(); //BAD: Hostname verification for rabbitmq ConnectionFactory is not enabled
}
}
References¶
SSLParameters.setEndpointIdentificationAlgorithm documentation.
RabbitMQ: ConnectionFactory.enableHostnameVerification documentation.
RabbitMQ: Using TLS in the Java Client.
CVE-2018-17187: Apache Qpid Proton-J transport issue with hostname verification.
CVE-2018-8034: Apache Tomcat - host name verification when using TLS with the WebSocket client.
CVE-2018-11087: Pivotal Spring AMQP vulnerability due to lack of hostname validation.
CVE-2018-11775: TLS hostname verification issue when using the Apache ActiveMQ Client.
Common Weakness Enumeration: CWE-273.