简体   繁体   English

如何防止LDAP注入

[英]how to protect against LDAP Injection

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

When constructing LDAP filters you must ensure that filter values are handled according to RFC2254 : 构建LDAP过滤器时,必须确保根据RFC2254处理过滤器值:

Any control characters with an ACII code < 32 as well as the characters with special meaning in LDAP filters "*", "(", ")", and "\\" (the backslash) are converted into the representation of a backslash followed by two hex digits representing the hexadecimal value of the character. 任何具有ACII代码<32的控制字符以及在LDAP过滤器中具有特殊含义的字符“*”,“(”,“)”和“\\”(反斜杠)都将转换为反斜杠的表示形式,然后是两个十六进制数字,表示字符的十六进制值。

Zend_Ldap for example uses the following routine 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);
    }
}
//[...]

One item to consider is that an LDAP bind with a Username (DN) but no password is considered an anonymous bind. 需要考虑的一个问题是,使用用户名(DN)但没有密码的LDAP绑定被视为匿名绑定。 Therefore should you test to see if the passed credentials can bind via LDAP to validate the user, if they pass a blank password, and you passed it through as is, you could let someone in incorrectly. 因此,您应该测试以查看传递的凭据是否可以通过LDAP绑定以验证用户,如果他们传递了空白密码,并且您按原样传递,则可能会让某人处于错误状态。

In PHP 5.6+ you should be using the ldap_escape function for filter values and RDNs. 在PHP 5.6+中,您应该将ldap_escape函数用于过滤器值和RDN。 Such as: 如:

// 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";

Additionally, if you're accepting user input for attribute names in searches you should be validating that it's an acceptable OID or attribute name. 此外,如果您在搜索中接受用户输入的属性名称,则应验证它是否为可接受的OID或属性名称。 You can do that with a function like this: 你可以用这样的函数做到这一点:

/**
 * 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)";

In most cases it is using a read-only account for LDAP. 在大多数情况下,它使用LDAP的只读帐户。 Since LDAP is poor at writes updates only occur in very small sections of the application where another account can be used. 由于LDAP写入较差,更新只发生在可以使用其他帐户的应用程序的非常小的部分。

Even then the query language and the update language are completely separated. 即使这样,查询语言和更新语言也完全分开。

To protect against displaying unwanted information treat all user input as tainted and make sure tainted data is never used before being parsed, cleaned and properly escaped and copied to a clean variable. 为防止显示不需要的信息,请将所有用户输入视为污染,并确保在解析,清理并正确转义并复制到干净变量之前永远不会使用受污染的数据。

Similarly you might consider only picking the data you expect from the response and return that for display. 同样,您可能会考虑仅从响应中选择您期望的数据并将其返回以供显示。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM