Query to detect insecure LDAP endpoint configuration

This commit is contained in:
luchua-bc
2021-02-15 05:31:29 +00:00
parent 178c54e69b
commit 23f620d255
6 changed files with 175 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
public class InsecureLdapEndpoint {
public Hashtable<String, String> createConnectionEnv() {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "username");
env.put(Context.SECURITY_CREDENTIALS, "secpassword");
// BAD - Test configuration with disabled SSL endpoint check.
{
System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
}
// GOOD - No configuration to disable SSL endpoint check since it is enabled by default.
{
}
return env;
}
}

View File

@@ -0,0 +1,32 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Java versions 8u181 or greater have enabled LDAPS endpoint identification by default. Nowadays infrastructure services like LDAP are commonly deployed behind load balancers therefore the LDAP server name can be different from the FQDN of the LDAPS endpoint. If a service certificate does not properly contain a matching DNS name as part of the certificate, Java will reject it by default.</p>
<p>Instead of addressing the issue properly by having a compliant certificate deployed, frequently developers simply disable SSL endpoint check.</p>
<p>This query checks whether LDAPS endpoint check is disabled in system properties.</p>
</overview>
<recommendation>
<p>Replace any non-conforming LDAP server certificates to include a DNS name in the subjectAltName field of the certificate that matches the FQDN of the service.</p>
</recommendation>
<example>
<p>The following two examples show two ways of configuring SSL endpoint. In the 'BAD' case,
endpoint check is disabled. In the 'GOOD' case, endpoint check is left enabled through the default Java configuration.</p>
<sample src="InsecureSSLEndpoint.java" />
</example>
<references>
<li>
Oracle Java 8 Update 181 (8u181):
<a href="https://www.java.com/en/download/help/release_changes.html">Endpoint identification enabled on LDAPS connections</a>
</li>
<li>
IBM:
<a href="https://www.ibm.com/support/pages/how-do-i-fix-ldap-ssl-error-%E2%80%9Cjavasecuritycertcertificateexception-no-subject-alternative-names-present%E2%80%9D-websphere-application-server">Fix this LDAP SSL error</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,65 @@
/**
* @name Insecure LDAP Endpoint Configuration
* @description Java application configured to disable LDAP endpoint identification does not validate the SSL certificate to properly ensure that it is actually associated with that host.
* @kind problem
* @id java/insecure-ldap-endpoint
* @tags security
* external/cwe-297
*/
import java
/**
* The method to set a system property.
*/
class SetSystemPropertyMethod extends Method {
SetSystemPropertyMethod() {
this.hasName("setProperty") and
this.getDeclaringType().hasQualifiedName("java.lang", "System")
}
}
/**
* The method to set Java properties.
*/
class SetPropertyMethod extends Method {
SetPropertyMethod() {
this.hasName("setProperty") and
this.getDeclaringType().hasQualifiedName("java.util", "Properties")
}
}
/**
* The method to set system properties.
*/
class SetSystemPropertiesMethod extends Method {
SetSystemPropertiesMethod() {
this.hasName("setProperties") and
this.getDeclaringType().hasQualifiedName("java.lang", "System")
}
}
/** Holds if `MethodAccess` ma disables SSL endpoint check. */
predicate isInsecureSSLEndpoint(MethodAccess ma) {
(
ma.getMethod() instanceof SetSystemPropertyMethod and
(
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() =
"com.sun.jndi.ldap.object.disableEndpointIdentification" and
ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" //com.sun.jndi.ldap.object.disableEndpointIdentification=true
)
or
ma.getMethod() instanceof SetSystemPropertiesMethod and
exists(MethodAccess ma2 |
ma2.getMethod() instanceof SetPropertyMethod and
ma2.getArgument(0).(CompileTimeConstantExpr).getStringValue() =
"com.sun.jndi.ldap.object.disableEndpointIdentification" and
ma2.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "true" and //com.sun.jndi.ldap.object.disableEndpointIdentification=true
ma2.getQualifier().(VarAccess).getVariable().getAnAccess() = ma.getArgument(0) // systemProps.setProperties(properties)
)
)
}
from MethodAccess ma
where isInsecureSSLEndpoint(ma)
select ma, "SSL configuration allows insecure endpoint configuration"

View File

@@ -0,0 +1,2 @@
| InsecureLdapEndpoint.java:17:9:17:92 | setProperty(...) | SSL configuration allows insecure endpoint configuration |
| InsecureLdapEndpoint.java:48:3:48:34 | setProperties(...) | SSL configuration allows insecure endpoint configuration |

View File

@@ -0,0 +1,52 @@
import java.util.Hashtable;
import java.util.Properties;
import javax.naming.Context;
public class InsecureLdapEndpoint {
// BAD - Test configuration with disabled SSL endpoint check.
public Hashtable<String, String> createConnectionEnv() {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "username");
env.put(Context.SECURITY_CREDENTIALS, "secpassword");
// Disable SSL endpoint check
System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
return env;
}
// GOOD - Test configuration without disabling SSL endpoint check.
public Hashtable<String, String> createConnectionEnv2() {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "username");
env.put(Context.SECURITY_CREDENTIALS, "secpassword");
return env;
}
// BAD - Test configuration with disabled SSL endpoint check.
public Hashtable<String, String> createConnectionEnv3() {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://ad.your-server.com:636");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "username");
env.put(Context.SECURITY_CREDENTIALS, "secpassword");
// Disable SSL endpoint check
Properties properties = new Properties();
properties.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
System.setProperties(properties);
return env;
}
}

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-297/InsecureLdapEndpoint.ql