
Команды безопасности верят, что создать продукт без уязвимостей можно, внедряя различные инструменты и практики вроде SAST, DAST и WAF. Эти практики помогают выявить уязвимости в уже написанном коде и, возможно, предотвратить их эксплуатацию.
Но исправить найденные уязвимости или сделать продукт изначально безопасным могут только те, кто делает этот продукт — сами разработчики. Поэтому важно, чтобы они умели писать безопасный код, а не жаловались на специалистов по безопасности или средства защиты, которые мешают работать.
Меня зовут Артемий Богданов, я всю жизнь занимаюсь практической безопасностью — находил уязвимости в Uber, Yahoo и ВКонтакте, занимал призовые места в конкурсах PHDays, NeoQUEST и других CTF. И сейчас я расскажу, как разработчики, аналитики и тестировщики могут попробовать себя в роли хакеров, чтобы в итоге делать свои продукты безопасными.
Почему разработчики забивают на безопасность
Как рассуждают команды безопасности?
— Если за безопасность продукта отвечают разработчики, значит, нужно научить их практикам безопасной разработки.
Обычный подход к такому обучению — это курсы и, если повезет, какая-то практика.

Но есть несколько причин, по которым такой подход не работает:
Разработчикам неинтересно проходить курсы. Особенно если они скучные и основаны на оторванной от реальности теории. Потому что это отвлекает их от реальных задач, которые они делают каждый день.
Разработчики не доверяют командам безопасности. Потому что обычно они предлагают какой-то трэш или отношения с командой безопасности в принципе не очень хорошие, между ними не налажена связь.
Разработчики могут знать, как правильно, но все равно не делать или делать по-своему. Потому что так быстрее или потому что не считают это важным.
Хакер против разработчика: 5:0
К чему приводит такое «обучение»? Вот небольшой пример, основанный на реальных событиях.
В Bug Bounty крупной компании приходит репорт от пентестера — «белого» хакера, который нашел уязвимость и сообщает о ней.
Пентестер: Ребята, у вас в коде есть XSS-уязвимость.
Разработчик: Гуглим быстрое решение — использовать функцию htmlspecialchars:

Раз это XSS, значит, нужно спецсимволы перевести в HTML-сущности.
Добавил эту функцию, теперь все безопасно, давайте в релиз!
Пентестер: Это не сработает, потому что на самом деле функция htmlspatialcharts не кодирует одинарную кавычку, а здесь значение параметра тега было указано именно в одинарных кавычках.
Разработчик: Окей, добавим специальный флаг, который преобразует одинарную кавычку в HTML-сущность.
Пентестер: Не выйдет, потому что можно использовать псевдопротокол JavaScript, если написать JavaScript и поставить двоеточие.
Разработчик: Понятно, вырежем JavaScript с помощью функции str_replace и заменим все эти вхождения.
Пентестер: Опять нет — хакер может использовать разные регистры для того, чтобы обойти такую защиту.
Разработчик: Задача понятна, решение — использовать регистронезависимую функцию замены. Добавляем одну букву, получается str_ireplace.
Ну что, теперь кажется, что все безопасно? Конечно, нет, здесь все равно осталась проблема. Хакер может воспользоваться забавным трюком и поместить внутрь одного спецслова JavaScript другое.
Когда произойдет замена, и слово вырежется, вы увидите результат. В конечном счете все равно появился валидный payload. В итоге уязвимость все еще не исправлена.

Почему разработчик тратит так много времени на исправление кода, но он не становится безопасным? Потому что не всегда намерения разработчика и специалиста по безопасности совпадают.
Как синхронизировать интересы разработчика и специалиста по безопасности
Давайте разберемся, какие задачи есть у разработки и безопасности.
Что важно разработчику:
выпустить продукт вовремя,
сделать всю нужную функциональность,
написать качественный код.
Качество кода — это то, что делает разработчика счастливым. Для разработчика недопустимо, чтобы на проде была какая-то критичная бага. Ему в этот момент некомфортно, нужно сразу все исправить.
Что важно команде безопасности:
выявить уязвимости,
устранить угрозы,
снизить риски,
обеспечить соответствие требованиям,
сделать так, чтобы код был безопасным.
Чтобы синхронизировать задачи, нужно показать разработчику, что качественный код — это безопасный код:

Когда мы покажем, что намерения разработчика и специалиста по безопасности на самом деле совпадают, у разработчика появится мотивация писать безопасный код. А мотивированные разработчики сами попросят материалы по безопасной разработке, будут их изучать и проследят, чтобы продукт был безопасным.
Для того, чтобы связать качественный и безопасный код, можно обучать разработчиков в игровом формате и пригласить их на CTF. Но есть проблема — стандартный CTF тут не подойдет.
Почему CTF для команд безопасности не подходит для разработчиков
Все хакерские CTF, которые я видел и делал сам, не очень подходят для разработчиков. Задания в них часто синтетические и очень сложные, а связи с реальной работой почти нет.

Вот пример задания из CTF для специалистов по безопасности:

Придет ли такое разработчику в JIRA в реальной жизни разработчику? Вряд ли. Опытному сеньору — не студенту и не хакеру — некогда решать странные шарады.
Как сделать CTF, интересный для разработчиков
Чтобы CTF для разработчиков был интересным и эффективным — помогал писать безопасный код, — нужно соблюсти несколько правил:
CTF должен максимально реалистично имитировать бизнес-логику приложений. Желательно, если приложение будет похожим на тот продукт, который человек разрабатывает в рамках своих стандартных рабочих задач.
Когда мы проводили первый CTF в своей команде, то специально имитировали компанию, которая создает плюс-минус похожие продукты на рынке. Конечно, они были попроще, но тем не менее ребятам было интересно.
Еще можно использовать функциональность, которая всем понятна и известна. Например, это может быть имитация реального интернет-банка.
В CTF должны быть задачи для разработчиков разного уровня. Чтобы джуниоры, мидлы и сеньоры нашли для себя интересные задания и смогли их решить.
Все задания в CTF должны подчиняться общей логике. Классно, если все задания соберутся в общий сюжет, это вызовет дополнительный интерес.
Вот пример CTF для разработчиков, который сделали мы:

CTF имитирует онлайн-банк с обратной связью и всеми стандартными операциями типа различных мультивалютных счетов, карточек, перевода денег по номеру счета и карты.
Участники CTF регистрируют аккаунт в имитированном банке, их задача — все изучить и затем выполнить задания.
Вот пример задания для джунов:

Для поиска и эксплуатации уязвимостей в любой системе очень важно провести подготовительную, исследовательскую работу.
Вы сможете найти этот флаг, если внимательно изучите окружение и исходный код системы, доступные публично или после авторизации.
В этом примере разработчик сам должен увидеть, что ему нужно делать. Единственная подсказка — название задач, они могут навести его на мысли. При этом в основе задачи — реальные проблемы окружения, которые встречаются на каждом первом проекте.
Пример задания для продвинутых разработчиков:
Вы пошли в бар рядом с банком и случайно услышали разговор соседей, из которого поняли, что клиент с номером телефона 89000001001 совершал подозрительные операции в DarkNet.
Разберитесь с этим и выясните детали, чтобы получить флаг.
В основе этой задачи — реальные кейсы утечек и то, как их используют хакеры для взлома самых защищенных приложений.
Какие результаты дает CTF для команд разработки
Мы проводили такой CTF в разных командах, в сумме в нем поучаствовало больше тысячи человек. Вот какие выводы мы сделали:
Обычные разработчики становятся киберчемпионами. Те, кто не хотел участвовать в CTF и даже не думал, что разбирается в безопасности, проникались интересом, получали флаги и занимали призовые места.
Киберчемпионы становятся связующим звеном между безопасностью и остальными членами команды. Разработчики не любят ходить к специалистам по безопасности, потому что они все время мешают им в процессах. После CTF ситуация меняется: разработчики на практике понимают ценность безопасного кода и советуются с опытными коллегами из своих же команд.
Повышается качество внутреннего багбаунти. Разработчики, которые раньше не разбирались в теме, начинают понимать, что такое уязвимости, как их находить, эксплуатировать и закрывать. Они начинают лучше искать уязвимости в ваших внутренних продуктах и сообщать о них.
Улучшается коммуникация между разными командами в компании. Люди, которые разрабатывают абсолютно разные продукты в компании, которые вообще никогда друг друга не видели и не общались, наконец-то начинают взаимодействовать.
Например, в нашем CTF для разработчиков была такая особенность: разработчики могли общаться друг с другом во время различных атак. Вот пример такого общения:

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

Что же в этом особенного? Человек, который отправил такой payload знал, что получатель заходит в свой личный аккаунт в банке только через cURL, просто потому что боится, что его взломают и заберут все деньги. Поэтому он отправил такой payload, который показывает поздравление только при открытии через cURL. А если открыть тот же самый payload из браузера, то он просто украдет все ваши деньги, сменит пароль от аккаунта, и вы останетесь ни с чем.
С чего начать подготовку к CTF в своей команде
Может показаться, что организовать CTF для разработчиков сложно. На самом деле это не совсем так. Да, с конкретными заданиями может понадобиться помощь, но общую логику можно проработать уже сейчас.
Что для этого потребуется?
Соберите топ-10 проблем, уязвимостей и ошибок, которые допускают разработчики в актуальных контекстах. По нашему опыту, это могут быть XSS, IDOR, CSRF, работа с зависимостями и уязвимости округления. В больших компаниях могут быть проблемы с валидацией данных, защитой cookie, CSV-инъекциями, CSP и SQL без использования параметризированных запросов.
Посмотрите на систему обучения и курсы, которые вы даете своим разработчикам. Честно ответьте на вопросы: помогает ли это обучение решить топ-10 ваших проблем? Интересны ли эти курсы разработчикам?
Опишите требования для CTF на основе ваших уязвимостей и частых ошибок в безопасности.
Разработайте задания по принципам из пункта «Как придумать интересный CTF для разработчиков». Если не хотите разрабатывать его сами, CTF можно заказать.
Такой CTF заинтересует разработчика больше, чем скучные задачки, и после конкурса он начнет думать, как писать безопасный код на своей работе.
