<!DOCTYPE qhelp PUBLIC
  "-//Semmle//qhelp//EN"
  "qhelp.dtd">
<qhelp>
<overview>
<p>If an LDAP query is built using string concatenation, and the
components of the concatenation include user input, a user 
is likely to be able to run malicious LDAP queries.</p>
</overview>

<recommendation>
<p>If user input must be included in an LDAP query, it should be escaped to
avoid a malicious user providing special characters that change the meaning
of the query. If possible build the LDAP query using framework helper methods, for example
from Spring's <code>LdapQueryBuilder</code> and <code>LdapNameBuilder</code>,
instead of string concatenation. Alternatively, escape user input using an appropriate
LDAP encoding method, for example: <code>encodeForLDAP</code> or <code>encodeForDN</code>
from OWASP ESAPI, <code>LdapEncoder.filterEncode</code> or <code>LdapEncoder.nameEncode</code>
from Spring LDAP, or <code>Filter.encodeValue</code> from UnboundID library.</p>
</recommendation>

<example>
<p>In the following examples, the code accepts an "organization name" and a "username"
from the user, which it uses to query LDAP.</p>

<p>The first example concatenates the unvalidated and unencoded user input directly
into both the DN (Distinguished Name) and the search filter used for the LDAP query.
A malicious user could provide special characters to change the meaning of these
queries, and search for a completely different set of values. The LDAP query is executed
using Java JNDI API.
</p>

<p>The second example uses the OWASP ESAPI library to encode the user values
before they are included in the DN and search filters. This ensures the meaning of
the query cannot be changed by a malicious user.</p>

<sample src="LdapInjectionJndi.java" />

<p>The third example uses Spring <code>LdapQueryBuilder</code> to build an LDAP query. In addition to
simplifying the building of complex search parameters, it also provides proper escaping of any
unsafe characters in search filters. The DN is built using <code>LdapNameBuilder</code>, which also provides
proper escaping.</p>

<sample src="LdapInjectionSpring.java" />

<p>The fourth example uses <code>UnboundID</code> classes, <code>Filter</code> and <code>DN</code>, to construct a safe filter and
base DN.</p>

<sample src="LdapInjectionUnboundId.java" />

<p>The fifth example shows how to build a safe filter and DN using the Apache LDAP API.</p>

<sample src="LdapInjectionApache.java" />
</example>

<references>
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/LDAP_Injection_Prevention_Cheat_Sheet.html">LDAP Injection Prevention Cheat Sheet</a>.</li>
<li>OWASP ESAPI: <a href="https://owasp.org/www-project-enterprise-security-api/">OWASP ESAPI</a>.</li>
<li>Spring LdapQueryBuilder doc: <a href="https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/query/LdapQueryBuilder.html">LdapQueryBuilder</a>.</li>
<li>Spring LdapNameBuilder doc: <a href="https://docs.spring.io/spring-ldap/docs/current/apidocs/org/springframework/ldap/support/LdapNameBuilder.html">LdapNameBuilder</a>.</li>
<li>UnboundID: <a href="https://ldap.com/2018/05/04/understanding-and-defending-against-ldap-injection-attacks/">Understanding and Defending Against LDAP Injection Attacks</a>.</li>
</references>
</qhelp>
