>
>
>
Почему важно проверять значения парамет…

Никита Липилин
Статей: 32

Сергей Васильев
Статей: 96

Почему важно проверять значения параметров общедоступных методов

В данной заметке мы обсудим, почему PVS-Studio считает параметры общедоступных методов источниками небезопасных данных и может выдавать предупреждения, если такие параметры используются без проверок.

Дело в том, что излишнее доверие к внешним данным может быть причиной многих уязвимостей - SQLI, XSS, path traversal и т.п. Наиболее очевидные примеры источников внешних данных - значения параметров запросов или текст, который вводит пользователь (например, в некоторое поле).

Однако излишнее доверие к параметрам общедоступных методов также может быть опасно. Под общедоступными имеются в виду методы, которые могут быть вызваны из других сборок. Например, это public методы public классов. Скорее всего, подобные методы представляют собой API для взаимодействия с библиотекой.

В чём же опасность?

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

Разработчики же самой библиотеки могут рассчитывать на то, что на вход приходят уже проверенные данные. Следовательно, необходимости в их проверке нет.

Из-за этого может возникнуть ситуация, когда ни пользователь библиотеки, ни её разработчик не провели валидацию входных данных. Это может стать причиной возникновения уязвимостей в случае передачи злоумышленником скомпрометированных данных.

Примечание. Ниже разбираются примеры с диагностикой V5608 (поиск возможных SQL инъекций). Тем не менее, эта информация актуальная и для других диагностик из группы OWASP, считающих параметры публично доступных методов источниками заражённых данных.

Посмотрим, как это может выглядеть в коде:

public class DBHelper
{
  public void ProcessUserInfo(String userName)
  {
    ....
    var command = "SELECT * FROM Users WHERE userName = '" + userName + "'";
    ExecuteCommand(command);
    ....
  }

  private void ExecuteCommand(String rawCommand)
  {
    using (SqlConnection connection = new SqlConnection(_connectionString))
    {
      ....
      using (var sqlCommand = new SqlCommand(rawCommand, connection))
      {
        using (var reader = sqlCommand.ExecuteReader())
          ....
      }
    }
  }
}

Класс DBHelper предоставляет метод ProcessUserInfo для внешнего использования, так как он доступен из других сборок. Обратите внимание, что параметр этого метода - userName - никак не проверяется перед использованием. Значение, полученное извне, напрямую используется для создания команды (переменная command). Далее полученная команда передаётся в метод ExecuteCommand, где без проверки используется для создания объекта типа SqlCommand.

В данном случае анализатор сможет выдать предупреждение о возможной SQLI, если принять userName за источник опасных данных.

Теперь рассмотрим возможный вариант использования метода ProcessUserInfo внешним приложением:

static void TestHelper(DBHelper helper)
{
  var userName = Request.Form["userName"];
  helper.ProcessUserInfo(userName);
}

Разработчик, написавший данный фрагмент кода, может не иметь доступа к коду класса DBHelper и рассчитывать на то, что валидация входных данных будет происходить внутри метода ProcessUserInfo. Возникает ситуация, при которой ни текущий код, ни код метода ProcessUserInfo не провёл валидацию данных, а значит, приложение будет уязвимо перед SQL инъекциями.

При анализе кода метода TestHelper анализатор не сможет предупредить о возможной SQL инъекции, т.к. не имеет доступа к исходному коду метода ProcessUserInfo. Однако, как мы видим, ситуация опасная, и сообщить о ней хочется.

Поэтому анализатор выдаст предупреждение там, где он сможет это сделать, - при анализе исходного кода метода ProcessUserInfo. В данном случае будет выдано предупреждение V5608 на низком уровне достоверности.

Если вы не хотите видеть подобных предупреждений, то можете отключить их с помощью комментария вида //-V::5608:3 в .pvsconfig файле. Тогда предупреждения V5608 (SQLI) низкого уровня достоверности не попадут в отчёт. Более подробно про .pvsconfig-файлы можно почитать в документации (раздел "Подавление ложных предупреждений с помощью файлов конфигурации диагностик (.pvsconfig)").

Если же вы, напротив, считаете такие предупреждения крайне важными, то можете повысить их уровень достоверности до высокого, используя комментарий вида //V_LEVEL_1::5608. Подробности приводятся в главе "Как задать свой уровень для конкретной диагностики" в документации.