我们正在构建一个通过php使用LDAP的应用程序,我开始认为有什么可以注入到LDAP中,更好的是如何防止LDAP注入?
答案 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
);
}