Меньше багов богу разработки: плюсы, минусы и нюансы имплементации подхода Secure by design
По дефолту разработчики, стремясь достичь безопасности приложения, идут операционным путем: пишут тесты и делают ревью, чтобы устранять уязвимости уже по факту их выявления. Однако существует подход, в рамках которого классический комплекс мер становится не нужен, — все эти требования будут неявно выполнены за счет использования правильного дизайна и архитектуры системы.
Меня зовут Сергей Талантов, я — архитектор и Security Champion в команде KasperskyOS «Лаборатории Касперского» и занимаюсь разработкой продуктов, к которым предъявляются самые жесткие требования в плане безопасности. В этой статье расскажу про подход Secure by design: от теории (что это такое и какие виды этого подхода существуют, а также как и почему мы его применяем) к практике (паттерны безопасного дизайна и примеры их использования на С++).
Операционная и конструкционная безопасность ПО
Сперва немного теории, чтобы унифицировать термины, которые будут использоваться в статье.
Уязвимость (vulnerability) — недостаток в системе, используя который можно намеренно нарушить ее работоспособность и вызвать неправильную работу.
В общем случае не каждый баг — это уязвимость, и не каждой уязвимостью можно воспользоваться, чтобы совершить какое-либо враждебное действие. Для реализации такого действия нужен эксплойт.
Эксплойт (exploit) — вредоносный код или приложение, которые используют уязвимости в ПО.
Эксплуатация уязвимостей происходит через так называемую поверхность атаки.
Поверхность атаки (attack surface) — общее количество возможных уязвимых мест в ПО.
Если уязвимостей много, принято говорить, что поверхность атаки большая. Такая ситуация наталкивает на мысль, что кодовая база в принципе большая и/или код дырявый.
И еще немного о терминах, которыми обозначают безопасность. Справедливости ради, в английском языке их два — security (используется, когда необходимо показать, что системе ничто не угрожает извне) и safety (когда наша система никому не будет угрожать в случае взлома кода). И часто их смешивают в один термин, хотя в чем-то они противоположны. Но в сегодняшнем контексте оба будут использоваться как единое целое, и, говоря про безопасность, я буду подразумевать и информационную, и функциональную.
Операционная безопасность ПО
Классический цикл работы над релизом можно изобразить следующим образом:
Разработка включает две стадии — проектирование и непосредственно разработку (хотя в теории их может быть и больше). Они крутятся в некоторых итерациях, а на выходе мы получаем продукт.
Дальше обязательно выполняется ИБ-ревью для обеспечения безопасности разработки и безопасности продукта на выходе: выявление уязвимостей ПО, проверка явного нарушения целостности, доступности и конфиденциальности и так далее. Все эти действия выполняются явно, через код-ревью и тесты. На выходе мы получаем некоторое количество багов с особым приоритетом и которые, соответственно, обязательны для устранения.
И бывает, что для их исправления понадобится менять большую часть или даже всю архитектуру, после чего мы снова попадаем в цикл проектирования и разработки. На это уходит много времени. Ну и не забывайте про капасити команды: чтобы работа с багами не превратилась в бесконечное шествие по кругу, в проекте нужен эксперт по безопасности, который будет выявлять проблемы на всех стадиях разработки.
После ревью безопасников мы выходим на пентесты — так называемые тесты на проникновение (penetration tests), которые проводятся с имитацией реального взлома системы. На этом этапе история с переделыванием архитектуры может повториться. В этом заключаются очевидные минусы, которые поможет устранить подход Secure by design.
Конструкционная безопасность, или Secure by design
C Secure by design тот самый комплекс мер из предыдущего подхода проводить не нужно — мы неявно выполняем эти требования за счет использования правильного дизайна и архитектуры системы. Дальнейший разговор будет как раз о том, что значит «неявно».
В результате неявного выполнения требований мы получаем продукт, в котором не только есть фиксы всех явных уязвимостей, но который еще и готов к потенциальным не выявленным проблемам. Второе следствие — тот самый эксперт по информационной безопасности, который необходим был в предыдущем подходе, здесь в рамках команды особо не нужен. Достаточно следовать выбранным паттернам, моделям, методологии, контролировать, что мы используем их правильно, и иногда контролировать архитектуру в целом. Все это само по себе уже даст результат.
Цикл разработки немного меняется.
В стадию проектирования и разработки добавляется этап ревью архитектуры, на нем происходит проверка, соответствует ли архитектура, которую мы пытаемся имплементить, нашим паттернам (методологии, требованиям). Стадии с ревью безопасности и пентестами проводятся, как и в рамках предыдущего подхода. Но скорее всего баги, найденные на этих стадиях, будут относиться только к имплементации — их удастся исправить малой кровью. А на стадии пентестов их может не быть вовсе. Как говорится, меньше багов богу разработки