跳转至

LDAP Injection

LDAP注入

描述

LDAP注入(LDAP Injection)涉及利用使用用户输入生成LDAP语句的基于Web的应用程序。在应用程序未能正确清理用户输入的情况下,攻击者可以通过将特殊关键字注入查询来操纵LDAP语句,这种攻击类似于SQL注入。

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;

public class LDAPSearchExample {

    public static void main(String[] args) {
        // 来自用户的输入(请将其替换为您自己的输入机制)
        String userInput = "username"; // 用户提供的输入

        // LDAP连接参数
        String ldapURL = "ldap://your-ldap-server:389";
        String baseDN = "ou=users,dc=example,dc=com"; // 替换为您的基本DN

        // 设置用于创建初始上下文的环境
        Hashtable<String, String> env = new Hashtable<>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapURL);

        try {
            // 创建初始上下文
            LdapContext ctx = new InitialLdapContext(env, null);

            // 指定搜索过滤器
            String searchFilter = "(uid=" + userInput + ")";

            // 设置搜索控件
            SearchControls searchControls = new SearchControls();
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            // 执行搜索
            NamingEnumeration<SearchResult> results = ctx.search(baseDN, searchFilter, searchControls);

            // 遍历搜索结果
            while (results.hasMore()) {
                SearchResult result = results.next();
                // 根据需要处理结果(例如,打印属性)
                Attributes attributes = result.getAttributes();
                System.out.println("User found: " + attributes.get("cn").get());
            }

            // 关闭上下文
            ctx.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
const ldap = require('ldapjs');

const userInput = 'user123';
const ldapQuery = `(uid=${userInput})`; // 容易受到LDAP注入攻击

const client = ldap.createClient({
    url: 'ldap://example.com:389'
});

client.search('ou=users,dc=example,dc=com', {
    filter: ldapQuery,
}, (err, res) => {
    // 处理搜索结果
    res.on('searchEntry', (entry) => {
        // 处理条目
    });

    res.on('error', (err) => {
        console.error('Error:', err.message);
    });
});
<?php
// 容易受到LDAP注入攻击的PHP代码
$userInput = 'user123';
$ldapQuery = "(uid=$userInput)"; // 容易受到LDAP注入攻击

$ldapconn = ldap_connect("ldap://example.com");
ldap_bind($ldapconn, "cn=admin,dc=example,dc=com", "adminpassword");

$result = ldap_search($ldapconn, "ou=users,dc=example,dc=com", $ldapQuery);
$entries = ldap_get_entries($ldapconn, $result);

// 处理搜索结果
foreach ($entries as $entry) {
    // 处理条目
}

ldap_close($ldapconn);
?>

建议

为了降低LDAP注入的风险,请考虑以下建议:

  • 参数化查询: 使用参数化查询而不是直接拼接来构建LDAP查询。

  • 输入验证 / 清理: 实施输入验证以确保用户输入符合预期格式,并且不包含可能改变LDAP查询的特殊字符,还可以使用 LdapFilterEncode 等方法清理用户输入。

  • 使用自动防止LDAP注入的框架: 利用完善且安全的LDAP查询API或库,在构建LDAP查询时自动对用户输入进行编码。

  • 启用绑定认证: 如果攻击者设法执行LDAP注入,使用绑定认证(Bind Authentication)将限制LDAP服务器的攻击面。

  • 最小特权: 最小特权原则是一个经验法则,旨在最大限度地减少受损服务的影响。

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.directory.*;

public class LDAPSearchMitigatedExample {

    public static void main(String[] args) {
        // 来自用户的输入(请将其替换为您自己的输入机制)
        String userInput = "username"; // 用户提供的输入

        // LDAP连接参数
        String ldapURL = "ldap://your-ldap-server:389";
        String baseDN = "ou=users,dc=example,dc=com"; // 替换为您的基本DN

        // 设置用于创建初始上下文的环境
        Hashtable<String, String> env = new Hashtable<>();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, ldapURL);

        try {
            // 创建初始上下文
            LdapContext ctx = new InitialLdapContext(env, null);

            // 使用参数化查询来避免LDAP注入
            String searchFilter = "(uid={0})";
            Object[] filterArgs = {userInput};

            // 设置搜索控件
            SearchControls searchControls = new SearchControls();
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            // 执行搜索
            NamingEnumeration<SearchResult> results = ctx.search(baseDN, searchFilter, filterArgs, searchControls);

            // 遍历搜索结果
            while (results.hasMore()) {
                SearchResult result = results.next();
                // 根据需要处理结果(例如,打印属性)
                Attributes attributes = result.getAttributes();
                System.out.println("User found: " + attributes.get("cn").get());
            }

            // 关闭上下文
            ctx.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
// 包含输入验证和参数化查询的缓解后的JavaScript代码
const ldap = require('ldapjs');

const userInput = 'user123';
// 执行输入验证以确保userInput对于LDAP查询是安全的
if (isValidUserInput(userInput)) {
    const ldapQuery = `(uid=${userInput})`;
    const client = ldap.createClient({
        url: 'ldap://example.com:389'
    });

    client.search('ou=users,dc=example,dc=com', {
        filter: ldapQuery,
    }, (err, res) => {
        // 处理搜索结果
        res.on('searchEntry', (entry) => {
            // 处理条目
        });

        res.on('error', (err) => {
            console.error('Error:', err.message);
        });
    });
} else {
    console.log('Invalid userInput');
}

function isValidUserInput(userInput) {
    // 实施适当的输入验证逻辑
    // 例如,检查允许的字符、长度等。
    return /^[a-zA-Z0-9]+$/.test(userInput);
}
<?php
// 包含输入验证和参数化查询的缓解后的PHP代码
$userInput = 'user123';
// 执行输入验证以确保userInput对于LDAP查询是安全的
if (isValidUserInput($userInput)) {
    $ldapQuery = "(uid=$userInput)";
    $ldapconn = ldap_connect("ldap://example.com");
    ldap_bind($ldapconn, "cn=admin,dc=example,dc=com");

    $result = ldap_search($ldapconn, "ou=users,dc=example,dc=com", $ldapQuery);
    $entries = ldap_get_entries($ldapconn, $result);

    // 处理搜索结果
    foreach ($entries as $entry) {
        // 处理条目
    }

    ldap_close($ldapconn);
} else {
    echo 'Invalid userInput';
}

function isValidUserInput($userInput) {
    // 实施适当的输入验证逻辑
    // 例如,检查允许的字符、长度等。
    return preg_match('/^[a-zA-Z0-9]+$/', $userInput);
}
?>

链接

标准

  • GDPR:
    • ART_25
    • ART_32
  • PCI_STANDARDS:
    • REQ_6_2
    • REQ_6_3
    • REQ_6_4
    • REQ_6_5
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5
  • HIPAA_CONTROLS:
    • SECURITY212
    • SECURITY213
    • SECURITY255