Enhance the query and update qldoc

This commit is contained in:
luchua-bc
2021-02-15 21:38:54 +00:00
parent 23f620d255
commit 5ce3af0591
6 changed files with 149 additions and 43 deletions

View File

@@ -8,16 +8,11 @@ public class InsecureLdapEndpoint {
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.
{
}
// BAD - Test configuration with disabled SSL endpoint check.
{
System.setProperty("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
}
return env;
}
}

View File

@@ -5,8 +5,8 @@
<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>
<p>Instead of addressing the issue properly by having a compliant certificate deployed, frequently developers simply disable LDAPS endpoint check.</p>
<p>Failing to validate the certificate makes the SSL session susceptible to a man-in-the-middle attack. This query checks whether LDAPS endpoint check is disabled in system properties.</p>
</overview>
<recommendation>
@@ -14,9 +14,10 @@
</recommendation>
<example>
<p>The following two examples show two ways of configuring SSL endpoint. In the 'BAD' case,
<p>The following two examples show two ways of configuring LDAPS 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" />
<sample src="InsecureLdapEndpoint.java" />
<sample src="InsecureLdapEndpoint2.java" />>
</example>
<references>

View File

@@ -1,17 +1,15 @@
/**
* @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.
* @name Insecure LDAPS Endpoint Configuration
* @description Java application configured to disable LDAPS 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
* @id java/insecure-ldaps-endpoint
* @tags security
* external/cwe-297
*/
import java
/**
* The method to set a system property.
*/
/** The method to set a system property. */
class SetSystemPropertyMethod extends Method {
SetSystemPropertyMethod() {
this.hasName("setProperty") and
@@ -19,19 +17,22 @@ class SetSystemPropertyMethod extends Method {
}
}
/**
* The method to set Java properties.
*/
class SetPropertyMethod extends Method {
SetPropertyMethod() {
this.hasName("setProperty") and
this.getDeclaringType().hasQualifiedName("java.util", "Properties")
}
/** The class `java.util.Hashtable`. */
class TypeHashtable extends Class {
TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") }
}
/**
* The method to set system properties.
* The method to set Java properties either through `setProperty` declared in the class `Properties` or `put` declared in its parent class `HashTable`.
*/
class SetPropertyMethod extends Method {
SetPropertyMethod() {
this.getDeclaringType().getAnAncestor() instanceof TypeHashtable and
this.hasName(["put", "setProperty"])
}
}
/** The method to set system properties. */
class SetSystemPropertiesMethod extends Method {
SetSystemPropertiesMethod() {
this.hasName("setProperties") and
@@ -39,27 +40,62 @@ class SetSystemPropertiesMethod extends Method {
}
}
/** Holds if an expression is evaluated to the string literal `com.sun.jndi.ldap.object.disableEndpointIdentification`. */
predicate isPropertyDisableLdapEndpointId(Expr expr) {
expr.(CompileTimeConstantExpr).getStringValue() =
"com.sun.jndi.ldap.object.disableEndpointIdentification"
or
exists(Field f |
expr = f.getAnAccess() and
f.getAnAssignedValue().(StringLiteral).getValue() =
"com.sun.jndi.ldap.object.disableEndpointIdentification"
)
}
/** Holds if an expression is evaluated to the boolean value true. */
predicate isBooleanTrue(Expr expr) {
expr.(CompileTimeConstantExpr).getStringValue() = "true" // "true"
or
expr.(BooleanLiteral).getBooleanValue() = true // true
or
exists(MethodAccess ma |
expr = ma and
ma.getMethod().hasName("toString") and
ma.getQualifier().(FieldAccess).getField().hasName("TRUE") and
ma.getQualifier()
.(FieldAccess)
.getField()
.getDeclaringType()
.hasQualifiedName("java.lang", "Boolean") // Boolean.TRUE.toString()
)
}
/** Holds if `ma` is in a test class or method. */
predicate isTestMethod(MethodAccess ma) {
ma.getMethod() instanceof TestMethod or
ma.getEnclosingCallable().getDeclaringType().getPackage().getName().matches("%test%") or
ma.getEnclosingCallable().getDeclaringType().getName().toLowerCase().matches("%test%")
}
/** 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
)
isPropertyDisableLdapEndpointId(ma.getArgument(0)) and
isBooleanTrue(ma.getArgument(1)) //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
isPropertyDisableLdapEndpointId(ma2.getArgument(0)) and
isBooleanTrue(ma2.getArgument(1)) 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"
where
isInsecureSSLEndpoint(ma) and
not isTestMethod(ma)
select ma, "LDAPS configuration allows insecure endpoint identification"

View File

@@ -0,0 +1,17 @@
public class InsecureLdapEndpoint2 {
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");
// GOOD - No configuration to disable SSL endpoint check since it is enabled by default.
{
}
return env;
}
}

View File

@@ -1,2 +1,5 @@
| 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 |
| InsecureLdapEndpoint.java:19:9:19:92 | setProperty(...) | LDAPS configuration allows insecure endpoint identification |
| InsecureLdapEndpoint.java:50:9:50:40 | setProperties(...) | LDAPS configuration allows insecure endpoint identification |
| InsecureLdapEndpoint.java:68:9:68:40 | setProperties(...) | LDAPS configuration allows insecure endpoint identification |
| InsecureLdapEndpoint.java:84:9:84:94 | setProperty(...) | LDAPS configuration allows insecure endpoint identification |
| InsecureLdapEndpoint.java:102:9:102:40 | setProperties(...) | LDAPS configuration allows insecure endpoint identification |

View File

@@ -3,7 +3,9 @@ import java.util.Properties;
import javax.naming.Context;
public class InsecureLdapEndpoint {
// BAD - Test configuration with disabled SSL endpoint check.
private static String PROP_DISABLE_LDAP_ENDPOINT_IDENTIFICATION = "com.sun.jndi.ldap.object.disableEndpointIdentification";
// BAD - Test configuration with disabled LDAPS endpoint check using `System.setProperty()`.
public Hashtable<String, String> createConnectionEnv() {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
@@ -19,7 +21,7 @@ public class InsecureLdapEndpoint {
return env;
}
// GOOD - Test configuration without disabling SSL endpoint check.
// GOOD - Test configuration without disabling LDAPS 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");
@@ -32,7 +34,7 @@ public class InsecureLdapEndpoint {
return env;
}
// BAD - Test configuration with disabled SSL endpoint check.
// BAD - Test configuration with disabled LDAPS endpoint check using `System.setProperties()`.
public Hashtable<String, String> createConnectionEnv3() {
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
@@ -49,4 +51,56 @@ public class InsecureLdapEndpoint {
return env;
}
// BAD - Test configuration with disabled LDAPS endpoint check using `HashTable.put()`.
public Hashtable<String, String> createConnectionEnv4() {
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.put("com.sun.jndi.ldap.object.disableEndpointIdentification", "true");
System.setProperties(properties);
return env;
}
// BAD - Test configuration with disabled LDAPS endpoint check using the `TRUE` boolean field.
public Hashtable<String, String> createConnectionEnv5() {
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(PROP_DISABLE_LDAP_ENDPOINT_IDENTIFICATION, Boolean.TRUE.toString());
return env;
}
// BAD - Test configuration with disabled LDAPS endpoint check using a boolean value.
public Hashtable<String, String> createConnectionEnv6() {
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.put("com.sun.jndi.ldap.object.disableEndpointIdentification", true);
System.setProperties(properties);
return env;
}
}