Мы создаем приложение, которое использует LDAP через php, и я подумал, можно ли что-нибудь сделать с внедрением в LDAP, и еще лучше, как защититься от внедрения LDAP?
как защититься от LDAP Injection
Ответы (5)
При создании фильтров 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);
}
}
//[...]
array("\x5c", "\x2a", "\x28", "\x29")
фактически совпадает с array('\\', '*', '(', ')')
, в то время как RFC2254 требует, чтобы эти символы были заменены на '\5c'
, '\2a'
, '\28'
и '\29'
буквально.
- person Stefan Gehrig; 03.05.2017
Один момент, который следует учитывать, заключается в том, что привязка LDAP с именем пользователя (DN), но без пароля, считается анонимной привязкой. Поэтому вам следует проверить, могут ли переданные учетные данные связываться через LDAP для проверки пользователя, если они передают пустой пароль, а вы передали его как есть, вы можете ввести кого-то неправильно.
В PHP 5.6+ вы должны использовать функцию ldap_escape для значений фильтра. и РДН. Такие как:
// 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)";
В большинстве случаев для LDAP используется учетная запись только для чтения. Поскольку LDAP плохо записывает, обновления происходят только в очень небольших разделах приложения, где можно использовать другую учетную запись.
Даже в этом случае язык запросов и язык обновления полностью разделены.
Чтобы защититься от отображения нежелательной информации, рассматривайте все вводимые пользователем данные как испорченные и убедитесь, что испорченные данные никогда не используются, прежде чем они будут проанализированы, очищены, должным образом экранированы и скопированы в чистую переменную.
Точно так же вы можете выбрать только те данные, которые вы ожидаете от ответа, и вернуть их для отображения.