Movatterモバイル変換


[0]ホーム

URL:


CodeQL documentation
CodeQL resources

LDAP query built from user-controlled sources

ID: java/ldap-injectionKind: path-problemSecurity severity: 9.8Severity: errorPrecision: highTags:   - security   - external/cwe/cwe-090Query suites:   - java-code-scanning.qls   - java-security-extended.qls   - java-security-and-quality.qls

Click to see the query in the CodeQL repository

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.

Recommendation

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’sLdapQueryBuilder andLdapNameBuilder, instead of string concatenation. Alternatively, escape user input using an appropriate LDAP encoding method, for example:encodeForLDAP orencodeForDN from OWASP ESAPI,LdapEncoder.filterEncode orLdapEncoder.nameEncode from Spring LDAP, orFilter.encodeValue from UnboundID library.

Example

In the following examples, the code accepts an “organization name” and a “username” from the user, which it uses to query LDAP.

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.

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.

importjavax.naming.directory.DirContext;importorg.owasp.esapi.Encoder;importorg.owasp.esapi.reference.DefaultEncoder;publicvoidldapQueryBad(HttpServletRequestrequest,DirContextctx)throwsNamingException{StringorganizationName=request.getParameter("organization_name");Stringusername=request.getParameter("username");// BAD: User input used in DN (Distinguished Name) without encodingStringdn="OU=People,O="+organizationName;// BAD: User input used in search filter without encodingStringfilter="username="+userName;ctx.search(dn,filter,newSearchControls());}publicvoidldapQueryGood(HttpServletRequestrequest,DirContextctx)throwsNamingException{StringorganizationName=request.getParameter("organization_name");Stringusername=request.getParameter("username");// ESAPI encoderEncoderencoder=DefaultEncoder.getInstance();// GOOD: Organization name is encoded before being used in DNStringsafeOrganizationName=encoder.encodeForDN(organizationName);StringsafeDn="OU=People,O="+safeOrganizationName;// GOOD: User input is encoded before being used in search filterStringsafeUsername=encoder.encodeForLDAP(username);StringsafeFilter="username="+safeUsername;ctx.search(safeDn,safeFilter,newSearchControls());}

The third example uses SpringLdapQueryBuilder 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 usingLdapNameBuilder, which also provides proper escaping.

import staticorg.springframework.ldap.query.LdapQueryBuilder.query;importorg.springframework.ldap.support.LdapNameBuilder;publicvoidldapQueryGood(@RequestParamStringorganizationName,@RequestParamStringusername){// GOOD: Organization name is encoded before being used in DNStringsafeDn=LdapNameBuilder.newInstance().add("O",organizationName).add("OU=People").build().toString();// GOOD: User input is encoded before being used in search filterLdapQueryquery=query().base(safeDn).where("username").is(username);ldapTemplate.search(query,newAttributeCheckAttributesMapper());}

The fourth example usesUnboundID classes,Filter andDN, to construct a safe filter and base DN.

importcom.unboundid.ldap.sdk.LDAPConnection;importcom.unboundid.ldap.sdk.DN;importcom.unboundid.ldap.sdk.RDN;importcom.unboundid.ldap.sdk.Filter;publicvoidldapQueryGood(HttpServletRequestrequest,LDAPConnectionc){StringorganizationName=request.getParameter("organization_name");Stringusername=request.getParameter("username");// GOOD: Organization name is encoded before being used in DNDNsafeDn=newDN(newRDN("OU","People"),newRDN("O",organizationName));// GOOD: User input is encoded before being used in search filterFiltersafeFilter=Filter.createEqualityFilter("username",username);c.search(safeDn.toString(),SearchScope.ONE,safeFilter);}

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

importorg.apache.directory.ldap.client.api.LdapConnection;importorg.apache.directory.api.ldap.model.name.Dn;importorg.apache.directory.api.ldap.model.name.Rdn;importorg.apache.directory.api.ldap.model.message.SearchRequest;importorg.apache.directory.api.ldap.model.message.SearchRequestImpl;import staticorg.apache.directory.ldap.client.api.search.FilterBuilder.equal;publicvoidldapQueryGood(HttpServletRequestrequest,LdapConnectionc){StringorganizationName=request.getParameter("organization_name");Stringusername=request.getParameter("username");// GOOD: Organization name is encoded before being used in DNDnsafeDn=newDn(newRdn("OU","People"),newRdn("O",organizationName));// GOOD: User input is encoded before being used in search filterStringsafeFilter=equal("username",username);SearchRequestsearchRequest=newSearchRequestImpl();searchRequest.setBase(safeDn);searchRequest.setFilter(safeFilter);c.search(searchRequest);}

References


[8]ページ先頭

©2009-2025 Movatter.jp