Prevention of unauthorized data manipulation through LDAP queries
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Hashtable;
public class LDAPInjectionVulnerable {
public void doGet(HttpServletRequest request, HttpServletResponse response) {
String user = request.getParameter("user");
String pass = request.getParameter("pass");
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
env.put("java.naming.provider.url", "ldap://localhost:389/dc=example,dc=com");
DirContext ctx = null;
try {
ctx = new InitialDirContext(env);
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
String filter = "(uid=" + user + ")";
ctx.search("", filter, controls);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ctx != null) {
try {
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
In the above code, we have a servlet that accepts
user
and
pass
parameters from the HTTP request and uses these values directly to construct an LDAP filter
(uid=" + user + ")
.
This is a classic example of an LDAP injection vulnerability because the user input is not properly sanitized before being used to construct the LDAP query. An attacker could manipulate the
user
parameter value to alter the LDAP query's logic.
For example, if an attacker sends a request with
user
parameter as
*)(uid=*))(|(uid=*
, the resulting filter becomes
(uid=*)(uid=*))(|(uid=*)
, which will return all users, bypassing the intended filter logic.
This vulnerability allows an attacker to perform unauthorized actions, such as bypassing authentication, viewing sensitive information, or modifying data.
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Hashtable;
import javax.naming.directory.SearchResult;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
public class LDAPInjectionFixed {
public void doGet(HttpServletRequest request, HttpServletResponse response) {
String user = request.getParameter("user");
String pass = request.getParameter("pass");
// Validate and sanitize user input
if (!user.matches("^[a-zA-Z0-9]*$")) {
throw new IllegalArgumentException("Invalid user input");
}
Hashtable env = new Hashtable();
env.put("java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory");
env.put("java.naming.provider.url", "ldap://localhost:389/dc=example,dc=com");
DirContext ctx = null;
try {
ctx = new InitialDirContext(env);
SearchControls controls = new SearchControls();
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// Use parameterized queries
String filter = "(uid={0})";
Object[] filterArguments = new Object[]{user};
NamingEnumeration results = ctx.search("", filter, filterArguments, controls);
while (results.hasMore()) {
SearchResult searchResult = results.next();
Attributes attributes = searchResult.getAttributes();
Attribute attribute = attributes.get("uid");
if (attribute != null) {
String uid = (String) attribute.get();
// Perform further processing
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ctx != null) {
try {
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
The fixed code includes several measures to prevent LDAP injection attacks:
1. Input Validation and Sanitization: The user input is validated and sanitized using a regular expression to ensure it only contains alphanumeric characters. This helps to prevent any malicious LDAP injection payloads from being included in the query.
2. Parameterized Queries: Instead of concatenating the user input directly into the LDAP query string, the code uses parameterized queries. The user input is included as a separate argument to the
ctx.search()
method, which prevents any unintended modification of the query.
3. Limited Privileges: Although not shown in the code, it is recommended to ensure that the LDAP user used to connect to the server has limited privileges and only has access to the necessary resources. This helps to minimize the potential impact of any successful LDAP injection attacks.
4. Input Validation and Output Encoding: The code includes input validation to reject any input that does not conform to the expected format. Although not shown in the code, it is also recommended to encode any output that is generated based on user input to prevent any potential cross-site scripting (XSS) attacks.
5. Regular Updates and Patches: Although not shown in the code, it is recommended to keep the LDAP server software up to date with the latest security patches to mitigate any known vulnerabilities that could be exploited through LDAP injection attacks.