LDAP injection
Need
Prevention of LDAP injection attacks
Context
- Usage of Ruby for building dynamic and object-oriented applications
- Usage of net-ldap for LDAP (Lightweight Directory Access Protocol) operations
Description
Non compliant code
def search_ldap(query)
conn = Net::LDAP.new( :host => ldap_host, :port => ldap_port, :auth => { :method => :simple, :username => ldap_username, :password => ldap_password })
filter = Net::LDAP::Filter.construct("(&(objectclass=*)(cn=#{query}))")
treebase = "dc=example,dc=com"
conn.search(:base => treebase, :filter => filter)
end
In the above code, the search_ldap method constructs an LDAP filter using untrusted data (the query parameter). The filter is constructed by interpolating the query directly into the filter string. If an attacker can control the query
parameter, they can potentially modify the LDAP filter in unexpected ways, leading to an LDAP Injection vulnerability.
For example, an attacker could provide a query
value of *))(|(cn=*
, which would modify the filter to return all objects in the directory, regardless of their cn attribute. This could lead to unauthorized disclosure of information or manipulation of the LDAP directory.
The vulnerability lies in the line:
filter = Net::LDAP::Filter.construct("(&(objectclass=*)(cn=#{query}))")
Here, the query
parameter is directly embedded into the LDAP filter without any sanitization or encoding, allowing potential LDAP Injection attacks.
Steps
- Validate and sanitize user input before using it in LDAP queries.
- Use parameterized queries or prepared statements to build LDAP queries.
- Avoid concatenating user input directly into the LDAP query string.
- Implement proper input validation to ensure that only expected characters are allowed.
- Implement proper input encoding to prevent special characters from being interpreted as LDAP query syntax.
- Use LDAP query libraries or frameworks that provide built-in protection against LDAP injection.
- Regularly update and patch the LDAP server to mitigate any known vulnerabilities.
- Implement strong authentication and authorization mechanisms to restrict access to the LDAP server.
- Monitor and log LDAP queries for suspicious or malicious activities.
- Educate developers about the risks of LDAP injection and provide secure coding guidelines.
Compliant code
def search_ldap(query)
conn = Net::LDAP.new( :host => ldap_host, :port => ldap_port, :auth => { :method => :simple, :username => ldap_username, :password => ldap_password })
query = Net::LDAP::Filter.escape(query)
filter = Net::LDAP::Filter.construct("(&(objectclass=*)(cn=#{query}))")
treebase = "dc=example,dc=com"
conn.search(:base => treebase, :filter => filter)
end
The updated code now includes a call to Net::LDAP::Filter.escape(query)
. This method call is used to sanitize the user input query
before it is used in the LDAP query. The Net::LDAP::Filter.escape
method escapes any special characters in the input string that could be used to manipulate the LDAP query.
This is a critical step in preventing LDAP injection attacks, as it ensures that user input cannot modify the structure of the LDAP query. By escaping special characters, we ensure that they are treated as literal characters in the query string, rather than being interpreted as LDAP query syntax.
This is a simple and effective way to prevent LDAP injection attacks, but it should be used in conjunction with other security measures, such as input validation, using parameterized queries or prepared statements, and implementing strong authentication and authorization mechanisms. Regularly updating and patching the LDAP server, monitoring and logging LDAP queries, and educating developers about secure coding practices are also important steps in maintaining a secure system.