如何防止LDAP注入

时间:2010-08-18 18:34:07

标签: php ldap code-injection

我们正在构建一个通过php使用LDAP的应用程序,我开始认为有什么可以注入到LDAP中,更好的是如何防止LDAP注入?

5 个答案:

答案 0 :(得分:9)

构建LDAP过滤器时,必须确保根据RFC2254处理过滤器值:

  

任何带有ACII的控制字符   代码< 32以及人物   在LDAP过滤器中具有特殊含义   “*”,“(”,“)”和“\”(反斜杠)   转换为表示   反斜杠后跟两个十六进制   表示十六进制的数字   角色的价值。

例如,

Zend_Ldap使用以下例程

//[...]
$val = str_replace(array('\\', '*', '(', ')'), array('\5c', '\2a', '\28', '\29'), $val);
for ($i = 0; $i<strlen($val); $i++) {
    $char = substr($val, $i, 1);
    if (ord($char)<32) {
        $hex = dechex(ord($char));
        if (strlen($hex) == 1) $hex = '0' . $hex;
        $val = str_replace($char, '\\' . $hex, $val);
    }
}
//[...]

答案 1 :(得分:2)

要考虑的一个问题是,使用用户名(DN)但没有密码的LDAP绑定被视为匿名绑定。因此,您应该测试以查看传递的凭据是否可以通过LDAP绑定以验证用户,如果他们传递了空白密码,并且您按原样传递,则可能会让某人处于错误状态。

答案 2 :(得分:2)

在PHP 5.6+中,您应该使用ldap_escape函数来过滤值和RDN。如:

// Escaping an LDAP filter for ldap_search ...
$username = ldap_escape($username, null, LDAP_ESCAPE_FILTER);
$filter = "(sAMAccountName=$username)";

// Escaping a DN to be used in an ldap_add, or a rename...
$rdn = ldap_escape('Smith, John', null, LDAP_ESCAPE_DN);
$dn = "cn=$rdn,dc=example,dc=local";

此外,如果您在搜索中接受用户输入的属性名称,则应验证其是否为可接受的OID或属性名称。你可以用这样的函数来做到这一点:

/**
 * Validate an attribute is an OID or a valid string attribute name.
 *
 * @param string
 * @return bool
 */
function isValidAttributeFormat($value)
{
    $matchOid = '/^[0-9]+(\.[0-9]+?)*?$/';
    $matchDescriptor = '/^\pL([\pL\pN-]+)?$/iu';

    return preg_match($matchOid, $value) 
        || preg_match($matchDescriptor, $value);
}

$attribute = 'sAMAccountName';
$value = 'foo';

if (!isValidAttributeFormat($attribute)) {
    throw new \InvalidArgumentException(sprintf('Invalid attribute name: %s', $attribute));
}

$value = ldap_escape($value, null, LDAP_ESCAPE_FILTER);
$filter = "($attribute=$value)";

答案 3 :(得分:1)

在大多数情况下,它使用LDAP的只读帐户。由于LDAP写入较差,更新只发生在可以使用其他帐户的应用程序的非常小的部分。

即使这样,查询语言和更新语言也完全分开。

为防止显示不需要的信息,请将所有用户输入视为污染,并确保在解析,清理并正确转义并复制到干净变量之前永远不会使用受污染的数据。

同样,您可能会考虑仅从响应中选择您期望的数据并将其返回以供显示。

答案 4 :(得分:0)

function ldap_quote($str) {
    return str_replace(
            array( '\\', ' ', '*', '(', ')' ),
            array( '\\5c', '\\20', '\\2a', '\\28', '\\29' ),
            $str
    );
}