﻿# Java, Taint и SAST: что это и зачем, и причём здесь ГОСТ 71207

На Java пишется огромное количество серверного кода\. Отсюда следует, что написанные на ней веб\-приложения должны быть устойчивы к специальным уязвимостям\. И эта небольшая статья как раз про один из способов борьбы с ними — SAST\. И ещё про то, что такое taint\-анализ и как он во всём этом участвует\. 

![1214_sast_is_comming_ru/image1.png](https://import.viva64.com/docx/blog/1214_sast_is_comming_ru/image1.png)

## О чём статья

В рамках нашего Java\-анализатора реализованы механизмы, которые позволят нам создавать диагностики, связанные с поиском использования потенциально опасных данных, попавших в программу извне\. Анализаторы PVS\-Studio для C\+\+ и C\# уже давно так умеют, вот и до Java добрались\.

В этой статье \(без закапывания в технические подробности\) расскажу, что такое поиск использования недостоверных \(потенциально опасных\) данных, и почему уметь такое — круто\. Если же, напротив, вы хотите ознакомиться с этим вопросом более подробно с точки зрения теории — тимлид нашего Java\-отдела написал об этом [статью](https://pvs-studio.ru/ru/blog/posts/java/1198/)\. Если вам это интересно, то рекомендую почитать\.

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

## Про уязвимости

Уязвимость — это проблемное место в программе, которое можно использовать для нарушения её работы\.

Для их выявления используется большое количество различных тестов\. Использовать их для обеспечения безопасности приложения — правильно и нужно, но осуществляются они на этапе тестирования\. А если я скажу, что обнаружить уязвимости можно раньше?

Здесь нас дорога приводит к понятию SAST\.

### SAST

SAST \(Static Application Security Testing\) — это методология тестирования, при которой код программы анализируется на наличие потенциальных уязвимостей\.

Под потенциальными уязвимостями подразумеваются "дефекты" в коде\. Дефектами они называются потому, что при определённом стечении обстоятельств их могут использовать злоумышленники, чтобы нарушить работу ПО\. 

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

И SAST\-специализированное ПО как раз нацелено на выявление потенциальных уязвимостей\. Одно из главных преимуществ использования SAST — их обнаружение прямо на этапе разработки приложения\. 

Почему это хорошо — расскажу далее\.

### SAST и удешевление разработки

Мы часто посещаем различные тематические конференции\. И если тема доклада касается статического анализа, мы говорим об одном очень важном преимуществе его использования — значительном уменьшении стоимости разработки\. Вернее, стоимости исправления ошибки\. Но, поскольку оба этих понятия тесно взаимосвязаны, я позволил себе такое обобщение\.

За счёт чего уменьшается стоимость?

Вопрос о цене исправления ошибки подняли в [NIST](https://www.nist.gov/) \(National Institute of Standards and Technology\)\. В своём исследовании они рассмотрели, как увеличивается стоимость исправления уязвимости в зависимости от того, на каком этапе цикла разработки ПО она была обнаружена\.

![1214_sast_is_comming_ru/image2.png](https://import.viva64.com/docx/blog/1214_sast_is_comming_ru/image2.png)

Как вы можете видеть, рост экспоненциальный\. И это логично\.

Исправление уязвимостей после релиза обходится дорого: разработчикам приходится отвлекаться от текущих задач, возвращаться к старому коду, что требует времени и ресурсов\. 

Но дела будут обстоять ещё хуже, если уязвимость, к примеру, позволяет манипулировать внутренними данными ПО — злоумышленники могут их удалить\. Думаю, вы представляете, какие убытки понесёт компания, если они просто возьмут и снесут базу данных\. Или обнародуют её\. Ну и помимо финансовых потерь, не стоит забывать о репутационных рисках\.

На этапе разработки устранение проблем требует меньше усилий и снижает затраты\.

Различных уязвимостей сейчас очень много\. Какие из них должно находить SAST\-решение? "Те, которым чаще всего сейчас подвергаются приложения" — звучит довольно логично\. Надеюсь, и вы так думаете\.  

## OWASP и его Top Ten

[OWASP](https://owasp.org/) \(Open Worldwide Application Security Project\) — это некоммерческий фонд, занимающийся повышением безопасности ПО\. С 2004 года зарегистрирован в США как некоммерческая благотворительная организация\. 

Фонд публикует большое количество материалов на тему безопасной разработки ПО\. Все они лежат в открытом доступе\. Также он проводит конференции и встречи, оказывает поддержку Open Source\.

**OWASP Top Ten** — проект OWASP, представляющий из себя отчёт о самых критичных уязвимостях веб\-приложений\. Он представлен в виде рейтинга, где каждая позиция объединяет группу схожих уязвимостей\. Порядок в списке зависит от множества факторов: потенциального ущерба, частоты встречаемости и простоты эксплуатации злоумышленниками\.

Особенность OWASP Top Ten в том, что он составляется на основе реально выявленных уязвимостей\. Сведения о них собираются раз в несколько лет и поставляются из следующих источников:

* специалисты и консультанты по информационной безопасности;
* Bug bounty — платформа, которая выдаёт денежное вознаграждение за найденную уязвимость в реальном приложении;
* компании, разрабатывающие веб\-приложения\.

Из\-за того, что составлен он на основе реальных уязвимостей, тренды в рамках информационной безопасности отражаются в нём как нельзя точно\. Для составления актуального сейчас OWASP Top Ten 2021 было рассмотрено свыше 500 тысяч реальных проектов\. Отсюда и большое доверие со стороны компаний, заинтересованных в борьбе с уязвимостями в своих веб\-приложениях\. 

По словам из [пресс\-релиза OWASP Top Ten 2021](https://www.owasptopten.org/copy-of-the-owasp-top-ten-2021), за все годы работы топ стал "псевдостандартом", представляющим из себя базовый канон, которому необходимо соответствовать\. И с этим тяжело не согласиться\. Абсолютное большинство SAST\-решений ориентируются именно на него\.

У нас есть [страница](https://pvs-studio.ru/ru/pvs-studio/sast/owasptopten/), на которой мы регулярно отмечаем, какие из наших диагностик соответствуют категориям OWASP Top Ten\.

## Рассмотрим уязвимости поближе

Давайте рассмотрим некоторые уязвимости из списка OWASP Top Ten\.

Возьмём в пример SQL\-инъекцию\. Всё\-таки в нашем Java\-анализаторе диагностика вышла именно на неё :\) 

SQL\-инъекция — это уязвимость, позволяющая злоумышленнику внедрять свой код в запрос, направленный в базу данных\. Благодаря этому злоумышленник может манипулировать находящимися в ней данными, а в особых случаях — нарушить их конфиденциальность\. 

Реализация этой уязвимости возможна, когда пользовательский ввод используется в запросе напрямую и никак перед этим не обрабатывается и не проверяется\. 

Давайте рассмотрим на примере\. У нас есть сайт со статьями\. В нём есть форма поиска, чтобы было удобно искать публикации по названиям\. Поиск по названию будет происходить так:

1. Пользователь вводит название статьи;
1. Оно отправляется на сервер;
1. Затем название объединяется с запросом для базы данных;
1. Запрос отправляется в базу данных;
1. Оттуда на основе запроса возвращается результат;
1. Сервер возвращает результат пользователю\.

И в случае, если объединение данных извне с запросом произойдёт некорректно, в него может быть внедрён зловредный код\.

Если вы хотите посмотреть на пример, при котором возможно осуществление SQL\-инъекции, то далее будет код на Java с объяснениями\. 

### Небольшой пример SQL\-инъекции

Давайте взглянем на следующий код:

```cpp
@Controller("/demo")
public class DemoController {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @GetMapping("/demo_get")
    public Optional<DemoObject> demoEndpoint(
        @RequestParam("param") String param)
    {
        Optional<DemoObject> demoObj = demoExecute(param);
        return demoObj;
    }

    private Optional<DemoObject> demoExecute(String name) {
        String sql = "SELECT * FROM DEMO_TABLE WHERE field = '" + name + "'";
        DemoObject result = jdbcTemplate.queryForObject(sql, DemoObject.class);
        return Optional.ofNullable(result);
    }
}
```

Пример синтетический, но он отражает вполне реальную проблему: данные извне используются в запросе непроверенными и необработанными\. Такие ситуации могут быть и в реальных проектах\.

Теперь поподробнее\.

Нам извне приходит строка `param`\. Она передаётся в метод `demoExecute`\. В нём, в строке `sql`, формируется запрос к базе данных\. Происходит это путём сложения строки `sql` с пришедшим извне параметром\. После этого строка `sql` передаётся в метод `queryForObject`, который его исполняет\.

Если данные извне будут поступать такими, какими хочет разработчик, проблем не возникнет\. Однако стоит пользователю передать что\-то более специфичное, станет немного грустно\.

Что это за специфичное такое? Ну, например:

_' drop table DEMO\_TABLE; \-\-_

В таком случае строка `sql` будет следующей:

```cpp
SELECT * FROM DEMO_TABLE WHERE field = '' drop table DEMO_TABLE; --'
```

И что произойдёт? А произойдёт удаление нашей таблицы `DEMO_TABLE` из базы данных\.

Чтобы избежать такой серьёзной потери, нам нужно проверить/очистить данные извне перед формированием запроса\.

Как это можно сделать? Например, удалить ненужные нам символы из строки, что пришла извне:

```cpp
name = name.replaceAll("[;'%\"--]", "");
```

Однако стоит помнить, что защититься от SQL\-инъекций полностью таким образом **невозможно**\. Лучше использовать параметризированные запросы:

```cpp
private Optional<DemoObject> demoExecute(String name) {
    String sql = "SELECT * FROM DEMO_TABLE WHERE field = ?";
    DemoObject result = jdbcTemplate.queryForObject(
            sql,
            new Object[]{name},
            DemoObject.class
    );
    return Optional.ofNullable(result);
}
```

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

Объясняя вам этот пример, я использовал общие слова и формулировки\. Однако в рамках этой проблематики существует специальная терминология:

* переменная `param` — **потенциально** **заражённые данные**;
* метод `demoEndpoint` — **источник** заражённых данных;
* метод, в котором непроверенные заражённые данные способны навредить — **сток**\. В нашем случае это метод `queryForObject`;
* проверка/очистка данных — **санитизация\.**

К слову, срабатывание анализатора на приведённый участок кода будет выглядеть следующим образом:

[V5309](https://pvs-studio.ru/ru/docs/warnings/v5309/) Possible SQL injection\. Potentially tainted data in the 'sql' variable is used to create SQL command\. DemoController\.java 28, 20

### От кода к выводам

Если обобщить суть уязвимости, то выглядеть она будет так: непроверенные данные извне при попадании в определённое место программы способны нарушить ход её выполнения\.

Одна ли SQL\-инъекция работает по такому принципу? Нет, уязвимостей с подобным паттерном много\. Среди них:

* [path traversal](https://pvs-studio.ru/ru/blog/terms/6470/);
* [XSS\-инъекция](https://pvs-studio.ru/ru/blog/terms/6462/);
* [NoSQL\-инъекция](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/05.6-Testing_for_NoSQL_Injection);
* [инъекция команды уровня ОС](https://owasp.org/www-community/attacks/Command_Injection)\.

И множество других\. Все они входят в OWASP Top Ten\.

### Как такое ловить?

Нам, как статическому анализатору, необходимо научиться такое ловить\. Как это реализовать? Давайте я выделю основные моменты, которые нас интересуют:

1. Источники — места, откуда в программу приходят данные извне;
1. Стоки — ключевые точки, в которых непроверенные данные извне могут навредить;
1. Санитизация — процесс, при котором данные извне очищаются или проверяются;
1. [Межпроцедурный анализ](https://pvs-studio.ru/ru/blog/terms/6785/) — нужно уметь смотреть, что происходит с данными при кочевании от метода к методу, как это было в примере, что я приводил выше\.

И нам нужно проследить, как данные, пришедшие из источников, путешествуют по программе\. И в случае, если они попали в стоки несанитизированными, сообщить об этом\.

Так в игру и вступил taint\-анализ\.

<details>
   <summary>Есть желание закопаться?</summary>

У нас есть [статья](https://pvs-studio.ru/ru/blog/posts/java/1198/), где более подробно описывается реализация вышеописанных моментов\. Если стало интересно, рекомендую ознакомиться\.


</details>


## Hello, Taint

Процесс, что я описал выше, называется **анализом помеченных данных**\. Также его называют **анализом заражённых данных**, или, как я говорил выше, **taint\-анализом**\. Тут уж на ваш выбор\.

Наши старшие братья, C\# и C\+\+, уже давно так умеют\. Вот и мы решили, что нужно поспевать за ними\. Для реализации этого мы, помимо добавления новых механизмов, правили старые\. И впоследствии для добавления новых диагностик нам нужно будет ещё пройтись напильником и по нашему data\-flow, и по многим другим вещам\. Но фундамент заложен, чему мы несказанно рады\.

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

## Немного про ГОСТ

В 2024 году вышел [ГОСТ 71207\-2024](https://pvs-studio.ru/ru/blog/video/11054/), который описывает, как правильно использовать статический анализатор при разработке безопасного ПО\. И в нём также есть информация о том, что используемый статический анализатор должен уметь\. К слову, у нас есть [статья](https://pvs-studio.ru/ru/blog/posts/1204/), где на момент релиза 7\.34 описывается, каким из этих требований PVS\-Studio удовлетворяет\.

В ГОСТовской терминологии taint\-анализ называется "анализом помеченных данных"\. Обратимся к пункту 7\.4, который располагается в главе "Требования к методам анализа, реализованным в статическом анализаторе"\. Приведу его содержание в упрощённом виде: 

> "Статический анализатор должен реализовывать следующие методы анализа: \.\.\.; межпроцедурный и межмодульный контекстно\-чувствительный анализ помеченных данных;\.\.\."

Терминология для Java разработчика может показаться немного странной, но если перевести, то: межмодульный анализ — технология, выявляющая ошибки, которые возникают при взаимодействии процедур \(методов\), которые расположены в разных модулях \(файлах\)\.

И теперь это требование мы удовлетворяем\. Благодаря этому наш анализатор стал намного лучше и интереснее: реализация taint\-анализа для Java позволила нам закрыть один очень важный гештальт из ГОСТа\.

## Итог

Реализация taint\-анализа в рамках нашего Java анализатора PVS\-Studio приблизила нас к званию полноценного SAST\-решения\. Мы уже приступили к разработке диагностик, направленных на покрытие уязвимостей из классификации OWASP Top Ten \(и не только оттуда\)\. И с каждым релизом их будет становиться всё больше\.

Также мы внимательно относимся к ГОСТу, и в следующих релизах продолжим реализовывать механизмы, которые продолжат увеличивать степень соответствия ему\. 

Ну и, конечно, оставляю [ссылку](https://pvs-studio.ru/ru/pvs-studio/try-free/), по которой вы можете попробовать анализатор PVS\-Studio\.

Пришло время прощаться\. До скорых встреч\!