﻿# V5620\. OWASP\. Possible LDAP injection\. Potentially tainted data is used in a search filter\.

Анализатор обнаружил, что потенциально заражённые данные используются для формирования фильтра LDAP\-запроса\. Это может стать причиной LDAP\-инъекции в случае, если данные будут скомпрометированы\. По своей сути данная атака похожа на SQL\-инъекции\.

Уязвимости типа LDAP\-инъекции относятся к категории рисков [OWASP Top 10 Application Security Risks 2021: A3:2021\-Injection](https://owasp.org/Top10/A03_2021-Injection/)\.

Рассмотрим пример:

```cpp
public void Search()
{
  ....
  string user = textBox.Text;
  string password = pwdBox.Password;

  DirectoryEntry de = new DirectoryEntry();
  DirectorySearcher search = new DirectorySearcher(de);

  search.Filter = $"(&(userId={user})(UserPassword={password}))"; 
  search.PropertiesToLoad.Add("mail");
  search.PropertiesToLoad.Add("telephonenumber");
  SearchResult sresult = search.FindOne();
  if(sresult != null)
  {
    ....
  }
  ....
}
```

В данном примере формируется фильтр поиска для предоставления некоторых личных данных пользователю, обладающему подходящими логином и паролем\. В фильтре используются значения переменных 'user' и 'password', полученные из внешнего источника\. Использование данных подобным образом опасно, так как даёт злоумышленнику возможность подделки фильтра поиска\.

Для лучшего понимания атаки приведём несколько примеров\.

Если в 'user' будет записано "PVS", а в 'password' – "Studio", то получится следующий запрос:

```cpp
LDAP query: (&(userId=PVS)(UserPassword=Studio))
```

В этом случае мы получили от пользователя ожидаемые данные и если такая комбинация пользователя и пароля существует, то будет предоставлен доступ\.

Но допустим, что в переменных 'user' и 'password' будут записаны следующие значения:

```cpp
user: PVS)(userId=PVS))(|(userId=PVS)
password: Any
```

При подстановке этих строк в шаблон получится следующий фильтр:

```cpp
LDAP query: (&(userId=PVS)(userId=PVS))(|(userId=PVS)(UserPassword=Any))
```

При использовании такого фильтра поиска доступ будет предоставлен в любом случае, даже если злоумышленник введёт неверный пароль\. Это произойдёт из\-за того, что LDAP будет обрабатывать только первый фильтр, а \(\|\(userId\=PVS\)\(UserPassword\=Any\)\) просто проигнорирует\.

Чтобы защититься от подобной атаки, стоит проводить валидацию всех входных данных или экранировать все специальные символы в данных, которые приходят от пользователей\. Существуют методы, которые автоматически экранируют все небезопасные значения\.

Пример кода с использованием метода автоматического экранирования из пространства имён 'Microsoft\.Security\.Application\.Encoder':

```cpp
public void Search()
{
  ....
  string user = textBox.Text;
  string password = pwdBox.Password;

  DirectoryEntry de = new DirectoryEntry();
  DirectorySearcher search = new DirectorySearcher(de);

  user = Encoder.LdapFilterEncode(user);
  password = Encoder.LdapFilterEncode(password);

  search.Filter = $"(&(userId={user})(UserPassword={password}))";    
  search.PropertiesToLoad.Add("mail");
  search.PropertiesToLoad.Add("telephonenumber");
  SearchResult sresult = search.FindOne();
  if (sresult != null)
  {
    ....
  }
  ....
}
```

Анализатор также считает источниками небезопасных данных параметры методов, доступных из других сборок\. Более подробно эта тема раскрыта в заметке "[Почему важно проверять значения параметров общедоступных методов](https://pvs-studio.ru/ru/blog/posts/csharp/0835/)"\.

Рассмотрим пример:

```cpp
public class LDAPHelper
{
  public void Search(string userName)
  {
    var filter = "(&(objectClass=user)(employeename=" + userName + "))";
    ExecuteQuery(filter);
  }

  private void ExecuteQuery(string filter)
  {
    DirectoryEntry de = new DirectoryEntry();
    DirectorySearcher search = new DirectorySearcher(de);

    search.Filter = filter; 
    search.PropertiesToLoad.Add("mail");
    search.PropertiesToLoad.Add("telephonenumber");
    SearchResult sresult = search.FindOne();
    if (sresult != null)
    {
      ....
    }
  }
}
```

В данном случае анализатор выдаст предупреждение низкого уровня достоверности при анализе исходного кода метода 'Search' на вызов 'ExecuteQuery'\. PVS\-Studio отследил передачу небезопасных данных из параметра 'userName' в переменную 'filter' и после в 'ExecuteQuery'\.

Защита в таком случае не отличается от приведённой ранее\.

```cpp
public class LDAPHelper
{
  public void Search(string userName)
  {
    userName = Encoder.LdapFilterEncode(userName);
    var filter = "(&(objectClass=user)(employeename=" + userName + "))";
    ExecuteQuery(filter); 
  }

  private void ExecuteQuery(string filter)
  {
    DirectoryEntry de = new DirectoryEntry();
    DirectorySearcher search = new DirectorySearcher(de);

    search.Filter = filter;
    ....
  }
}
```