Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
Поймай уязвимость своими руками: пользо…

Поймай уязвимость своими руками: пользовательские аннотации C# кода

25 Окт 2024

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

1175_Custom_annotations_Cs_Article_ru/image1.png

Пара вводных слов

Сегодня мы поговорим о механизме пользовательских аннотаций в статическом анализаторе PVS-Studio и о том, как он может помочь в борьбе с уязвимостями. Стоит отметить, что идея добавить пользовательскую разметку в анализатор не нова. Её уже успешно внедрили в C++ часть PVS-Studio. О предпосылках появления C++ аннотаций, а также о их возможностях можно узнать в отдельной статье.

Команда разработки C# анализатора решила не отставать от своих коллег и принялась реализовывать пользовательские аннотации для своей части анализатора.

Уже неоднократно я употребил выражение "пользовательские аннотации". Если с пониманием первой части этого выражения не должно возникать проблем, то на второй следует заострить внимание. Под "аннотациями" в данном контексте подразумевается некоторая разметка, позволяющая анализатору получить дополнительную информацию об исходном коде. Например, разметив метод, мы можем подсказать анализатору, что этот метод всегда возвращает непроверенные внешние данные. Если подобные данные не обработать соответствующим образом, то при попадании в определённые места программы, они могут привести к появлению потенциальной уязвимости.

Что такое потенциальная уязвимость? Если вкратце, то это дефект, содержащийся в коде программы, который при некотором стечении обстоятельств может эксплуатировать злоумышленник. Более развёрнуто о потенциальных уязвимостях можно почитать здесь.

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

Реализация taint-анализа в PVS-Studio

В PVS-Studio taint-анализ реализован посредством анализа потока данных (data-flow), разметки источников и приёмников заражённых данных. Во время анализа просчитываются пути распространения заражённых данных. Если такие данные без проверки попадут в т.н. приёмник, то анализатор выдаст предупреждение о возможном дефекте безопасности. Это была демоверсия описания работы taint-анализа в PVS-Studio, но есть и полная :)

На данный момент в анализаторе существует 16 taint-диагностик, каждая из которых отвечает за конкретных дефект безопасности:

  • V5608 — SQL injection;
  • V5609 — Path traversal vulnerability;
  • V5610 — XSS vulnerability;
  • V5611 — Insecure deserialization vulnerability;
  • V5614 — XXE vulnerability;
  • V5615 — XEE vulnerability;
  • V5616 — Command injection;
  • V5618 — Server-side request forgery;
  • V5619 — Log injection;
  • V5620 — LDAP injection;
  • V5622 — XPath injection;
  • V5623 — Open redirect vulnerability;
  • V5624 — Configuration vulnerability;
  • V5626 — ReDoS vulnerability;
  • V5627 — NoSQL injection;
  • V5628 — Zip Slip vulnerability.

Рассмотрим пример потенциальной уязвимости, которую находит анализатор:

void ProcessRequest(HttpRequest request) 
{ 
  string name = request.Form["name"];

  string sql = $"SELECT * FROM Users WHERE name='{name}'";
  ExecuteReaderCommand(sql);

  .... 
}

void ExecuteReaderCommand(string sql) 
{
  using (var command = new SqlCommand(sql, _connection))
  { 
    using (var reader = command.ExecuteReader()) { .... } 
  } 
  .... 
}

В переменную name будет записано имя пользователя, полученное из стороннего источника. Впоследствии значение этой переменной выступает частью SQL-запроса.

Данный код уязвим к SQL-инъекциям, так как в нём непроверенные внешние данные используются для формирования запроса к базе данных.

К примеру, в параметре name может быть записано следующее значение:

'; DELETE FROM Users WHERE name != '

При подстановке этой строки в шаблон запроса получится следующая SQL-команда:

SELECT * FROM Users WHERE name='';
DELETE FROM Users WHERE name != ''

Выполнение такого запроса приведёт к удалению всех записей из таблицы Users (при условии, что для каждого пользователя задано значение столбца name).

Подобная потенциальная уязвимость будет найдена с помощью PVS-Studio.

Пользовательские аннотации

Примечание. На момент написания статьи в C# части анализатора реализованы пользовательские аннотации только для taint-анализа. Подобный способ разметки требуется для ГОСТ Р 71207–2024. Теперь PVS-Studio предоставляет пользователям возможность размечать источники (процедуры-источники) и приёмники (процедуры-стоки) чувствительных данных. Стоит отметить, что в будущем мы планируем расширить возможности пользовательских C# аннотаций (аннотации не только для taint-анализа).

Ранее я уже писал о том, что понимается под "аннотацией" в текущем контексте, но на всякий случай повторюсь. Под аннотацией подразумевается некоторая разметка, позволяющая анализатору получить дополнительную информацию об исходном коде.

В PVS-Studio начиная с версии 7.33 появился механизм, который позволит пользователям размечать источники, передатчики и приёмники небезопасных данных для C# проектов. Таким образом, анализатор сможет точнее искать потенциальные уязвимости для конкретного проекта.

Стоит уточнить, что в анализаторе уже есть разметка для большинства популярных библиотечных методов/конструкторов/свойств. Например, анализатор уже "из коробки" знает, что при передаче результата выполнения метода System.Console.ReadLine в конструктор System.Data.SqlClient.SqlCommand возможно возникновение SQL injection.

Если вкратце, то работает это за счёт того, что в анализаторе есть аннотации, которые говорят, что System.Console.ReadLine — источник taint-данных, а System.Data.SqlClient.SqlCommand — приёмник. Если в него попадают taint-данные, может возникнуть уязвимость SQL injection.

Вернёмся непосредственно к пользовательским аннотациям. Для большей наглядности давайте рассмотрим пример их использования.

Допустим, у нас в проекте имеется следующий класс:

namespace MyNamespace
{
  public class MyClass
  {
    public string GetUserInput() 
    {
      ....
    }

    public string ModifyCommand(string command, string commandAddition)
    {
      ....
    }

    public void ExecuteCommand(string command)
    {
      ....
    }
  }
}

Методы этого класса выполняют следующие действия:

  • GetUserInput возвращает некоторый пользовательский ввод;
  • ModifyCommand добавляет к уже существующей SQL-команде строку;
  • ExecuteCommand выполняет SQL-команду.

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

public static void ProcessUserInput(MyClass test)
{
  string userInput = test.GetUserInput();
  string modifiedCommand = test.ModifyCommand("I'm a sql command",
                                              userInput);
  test.ExecuteCommand(modifiedCommand);
}

В данном случае, пользовательский ввод без проверки попадает в метод, выполняющий SQL-команду. Как мы уже упоминали выше, это может привести к возникновению SQL Injection.

Чтобы анализатор отслеживал подобные случаи, нужно добавить ряд аннотаций методов. Содержимое файла с аннотациями будет выглядеть следующим образом:

{
  "version": 1,
  "language": "csharp",
  "annotations": [
    {
      "type": "method",
      "namespace_name": "MyNamespace",
      "type_name": "MyClass",
      "method_name": "GetUserInput",
      "returns": {
        "attributes": [
          "always_taint"
        ],
        "namespace_name": "System",
        "type_name": "String"
      }
    },
    {
      "type": "method",
      "namespace_name": "MyNamespace",
      "type_name": "MyClass",
      "method_name": "ModifyCommand",
      "params": [
        {
          "namespace_name": "System",
          "type_name": "String"
        },
        {
          "namespace_name": "System",
          "type_name": "String",
          "attributes": [
            "transfer_annotation_to_return_value"
          ]
        }
      ]
    },
    {
      "type": "method",
      "namespace_name": "MyNamespace",
      "type_name": "MyClass",
      "method_name": "ExecuteCommand",
      "params": [
        {
          "namespace_name": "System",
          "type_name": "String",
          "attributes": [
            "sql_injection_target"
          ]
        }
      ]
    }
  ]
}

Разберём, зачем нужна каждая из аннотаций:

  • Аннотация метода GetUserInput содержит информацию о том, что этот метод возвращает taint-данные.
  • Аннотация метода ModifyCommand содержит информацию о том, что при попадании taint-данных во второй аргумент, метод также вернёт taint.
  • Аннотация метода ExecuteCommand подсказывает анализатору, что при попадании taint-данных в первый аргумент возможно возникновение SQL Injection.

Таким образом, анализатор понимает, что taint-данные из GetUserInput передаются в ModifyCommand. После этого возвращаемое значение ModifyCommand также становится заражённым. Это значение передаётся в метод ExecuteCommand, что в свою очередь может привести к возникновению SQL Injection.

Если добавить аннотации в проект, который содержит использование ProcessUserInput, а потом проанализировать этот проект, получим следующее предупреждение:

V5608 [OWASP-5.3.4, OWASP-5.3.5] Possible SQL injection. Potentially tainted data in the 'modifiedCommand' variable is used to create SQL command.

Стоит отметить, что в файл с аннотациями можно добавить поле $schema. Благодаря этому полю, современные текстовые редакторы и IDE могут проводить валидацию, а также подсказывать возможные значения во время редактирования файла. О том, какие значения принимает поле $schema можно узнать в документации.

Более детально о возможностях пользовательских C# аннотаций можно почитать в документации.

Заключение

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

Если же составлять аннотации нет желания, то всегда можно положиться на разработчиков PVS‑Studio. Как мы уже упоминали выше, множество аннотаций библиотечных методов, конструкторов и свойств доступны сразу после установки. А потому остаётся только проверить свой проект :)

Популярные статьи по теме


Комментарии (0)

Следующие комментарии next comments
close comment form
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам