Раньше, когда мы нанимали новых специалистов, работа над кодом строилась так: пишем, проверяем, исправляем ошибки, проверяем ещё раз, снова переписываем и т.д. В итоге даже после испытательного срока разработчик тратил на фрагмент кода до 60 часов, а ревьюер — до 10. Но плановый аудит помог понять, что подход нужно менять.
Привет! Это SpaceWeb, на связи Виталий Киреев, я руковожу отделом исследований и разработок. В статье расскажу, как мы в компании внедрили стандарты работы с веб-уязвимостями и собственную методологию обучения сотрудников и каких результатов добились.

Как работали до внедрения стандартов
Мы нанимали сотрудников, у которых уже был опыт работы с веб-уязвимостями. Но рельеф знаний у всех был разный: например, разработчик мог хорошо разбираться в SQL-инъекциях, но ничего не понимать в XSS. В результате уровень безопасности их изначального кода был разным — первые три месяца приходилось тратить на код-ревью по 30–40 часов и разбирать каждую ошибку отдельно.
На подключение новых сервисов к API, таких как DBaaS, разработчик тратил 20–40 часов. Еще 2–4 часа уходило на код-ревью. Код мог вернуться на доработку от одного до трех раз. В итоге на новую фичу для API мы тратили 30–60 часов разработчика и 3–6 часов ревьюера. И даже тогда в код могли просачиваться потенциальные веб-уязвимости, которые отлавливали на этапе внутренней проверки безопасности.
Нюанс с код-ревью еще и в том, что в SpaceWeb нет выделенной команды ревьюеров. Проверкой и рецензированием кода занимаюсь я, как руководитель отдела, и другие опытные мидл- и сеньор-разработчики. Нам приходилось выделять много времени на проверку кода новых сотрудников даже после испытательного срока, и это было проблемой.
Осознали проблему — начались первые изменения
Подсветить проблему помог внешний аудит — тогда мы точно решили, что подход к разработке и работе с веб-безопасностью пора менять. Хотелось меньше следить за кодом, а для этого нужно было, чтобы все разработчики наших программных продуктов придерживались общих правил в разрезе безопасности.
В формате код-ревью новым сотрудникам было сложно учиться работать с веб-уязвимостями, потому что обратную связь они получали по каждой конкретной задаче. Так получалось хорошо отработать одни типы веб-уязвимостей, которые встречаются почти в каждой задаче по API, например RCE, и ни разу не столкнуться с более редкими — например, с инъекциями PHP-объектов через сериализацию. При этом разработчики всё равно должны учитывать разные типы уязвимостей и уметь отрабатывать их в коде.
Еще мы пробовали давать новым сотрудникам материалы для самостоятельного изучения, но это тоже не сработало. Поначалу предлагали разработчикам самим погружаться в популярные документы по веб-безопасности — например, OWASP Web Security Testing Guide, ver 4.1 и OWASP Developer Guide, ver 2. И дополнительно проходить курсы образовательной платформы Otus и Бауманского учебного центра «Специалист» по PHP-разработке, в которых были кусочки, посвященные веб-безопасности.
В итоге новым сотрудникам приходилось изучать огромное количество информации самим. Такой подход тоже не давал равномерных знаний по веб-безопасности для всех.
Тогда мы решили взять подготовку кадров на себя и внедрить внутренний стандарт работы с веб-уязвимостями.
Шаг 1. Разработка стандартов: что в них вошло
За основу взяли стандарты веб-безопасности OWASP. Для тех, кто не знает, — это международная некоммерческая организация, которая занимается вопросами обеспечения безопасности веб-приложений. Вместе с нашим отделом безопасности изучили весь список уязвимостей и отобрали только те, которые актуальны для нашего стека. Примеры к каждому типу уязвимости подобрали из предыдущих код-ревью и проверок службы безопасности.
В стандарты вошло 9 типов веб-уязвимостей. Их мы разбили на две группы: Server Side — для бэкендеров и Client Side — для фронтендеров.
Server Side | бэкенд | Client Side | фронтенд |
RCE (Remote Code Execution) | XSS (Cross-Site Scripting) |
LFI/RFI (File Include) | CSRF/XSRF (Cross-Site Request Forgery) |
SSTI (Server Side Template Injection) | CFT/Open Redirect |
XXE (XML External Entity) | |
SSRF (Server Side Request Forgery) | |
PHP Object Injection |
Структура корпоративных стандартов веб-безопасности получилась такой: тип уязвимости — пример — шаги для решения проблемы
На подготовку ушло два месяца. На выходе получили внутренний документ по работе с веб-уязвимостями, который базируется на международных стандартах OWASP, нашей собственной практике и полностью адаптирован под структуру компании. По этим стандартам мы начали работать с июля 2020 года.
Шаг 2. Обучение сотрудников: основные этапы
Как закончили с разработкой стандартов, начали продумывать методологию обучения. Обучение разбили на три этапа: вебинар → практика → аттестация. По этой схеме мы работаем до сих пор.
Вебинар
Для каждого нового сотрудника я сам провожу двухчасовую онлайн-встречу, на которой знакомлю его со стандартами. Почему не в записи? Опыт с курсами показал, что так информация плохо усваивается: лекцию либо смотрят вполглаза и пропускают важное, либо, досмотрев до конца, забывают, что было в начале.
Еще знания у всех разработчиков разные, а запись не позволяет эффективно закрыть пробелы. Зато в режиме реального времени мы можем выяснить, каких знаний не хватает, и сделать на этом акцент.
Практика
После презентации разработчик идет применять теорию на практике. Уже на испытательном сроке мы даем новым сотрудникам реальные задачи, в которых нужно применять стандарты веб-безопасности. Например, вот такое решение ждем от разработчика при работе с XSS:
header("X-XSS-Protection: 1; mode=block");
header("X-Frame-Options: SAMEORIGIN");
header("Content-Security-Policy: frame-ancestors 'self' https://*.sweb.ru;");
У каждого есть наставник, которому можно задать вопросы, а код проходит скрупулезную проверку с разбором ошибок.
Аттестация
В конце испытательного срока проверяем, как новичок усвоил стандарты. Аттестация состоит из двух частей. Мы работаем по Agile и первым делом смотрим последние четыре спринта сотрудника и количество уязвимостей в коде, которые обнаружили на этапе QA. Нормальный показатель — 1–2 бага на 10 задач.
Дальше сотрудник решает тест из 2–6 вопросов. У бэкендеров вопросов больше, чем у фронтендеров, поскольку и типов уязвимостей в серверной части больше.
В тесте можем показать кусок кода и спросить, почему он не соответствует стандартам веб-безопасности. Или, наоборот, просим разработчика привести пример кода из проекта, где полностью соблюдены правила по очистке входящих данных, и аргументировать ответ.
Пример кода, в котором есть проблема с безопасностью:
$domain = strval($_POST['domain']);
$email = strval($_POST['email']);
Решение этой проблемы:
$domain = filter_var($_POST['domain'], FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$email = filter_var($_POST['email'], FILTER_SANITIZE_EMAIL);
Чтобы пройти аттестацию в конце испытательного, нужно правильно ответить на 75% вопросов. Если что-то идет не так, мы вынуждены расстаться с сотрудником.
После успешной аттестации по веб-безопасности, сотрудники могут начинать работать с задачами, которые напрямую связаны с персональными данными пользователей, паролями.
Обучение занимает много времени, но это инвестиция в команду. Можно было выбрать тотальный контроль и полный код-ревью, но мы решили пойти другим путем — задать определенный уровень веб-безопасности, которого должны придерживаться все наши разработчики. Мы сделали ставку на такой подход, будучи уверенными, что это сократит нагрузку и на меня, и на других ревьюеров и снизит уровень веб-уязвимостей, которые мы обнаруживаем на код-ревью. И не ошиблись.
Результаты: трудозатраты на код-ревью сократились до 70%, а безопасность кода выросла в 10 раз
После прохождения аттестации каждый разработчик обязан учитывать стандарты веб-безопасности в своем коде.
К примеру, есть правила по очистке входящих данных: верификация email, строковых и числовых данных. Для этого есть конкретные фильтры, валидаторы, которые разработчик должен использовать, — это зафиксировано в стандарте.
Пример использования встроенного валидатора:
if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
throw new \InvalidArgumentException('Status code must be an integer value.');
}
В результате мы твердо знаем, что все данные, которые получаем на входе, проходят проверку. И так во всём. Эта работа упростила ревью кода и во время испытательного срока новых сотрудников, и после.
Чтобы оценить, как изменились времязатраты на типовые задачи, мы применили диаграмму Ганта, в которой фиксируем продуктовый план. Оказалось, что затраты компании на код-ревью в период адаптации снизились минимум в три раза — теперь в первые три месяца работы новичка мы тратим на проверку кода 10–15 часов.
Еще у нас есть тайм-трекинг в Jira: напротив каждого слота сотрудники отмечают, на что ушло время. Например, три часа на код-ревью. Так выяснили, что после старатизации работы с веб-уязвимостями, время на код-ревью сократилось на 50–70%, а скорость написания кода выросла на 20%. Такой подход позволяет ревьюеру вместо рецензирования кода заниматься непосредственно своими задачами — разработкой или оптимизацией программной архитектуры.
Так изменились трудозатраты разработчиков и ревьюеров на фичи для API:
Трудозатраты | До | После |
Разработчик | 30–60 часов | 25–50 часов |
Ревьюер | 3–10 часов | 1–3 часа |
Разработчики изначально предусматривают в своем коде стандарты веб-безопасности, и в результате на код-ревью и исправление ошибок тратится меньше времени
Качество кода тоже выросло. Для QA у нас есть отдельный баг-трекер в Jira, где отмечается количество багов и возвратов задач на доработку. Статистика показала, что уязвимостей на этапе QA стало в 10 раз меньше. Раньше потенциальные уязвимости находили в каждой задаче, сейчас — только в одной из десяти. Там, где есть ошибки, неизбежен процесс их исправления и повторной проверки — это увеличивает сроки и стоимость разработки, так что стандартизация экономит компании не только время, но и деньги.
Пользу от внедрения стандартов ощутили и сотрудники. Кто-то раньше с веб-безопасностью сталкивался больше в теории, чем на практике. Некоторые разработчики на прошлых работах узнавали о требованиях к веб-безопасности из документации к проекту или от старших коллег уже после того, как допускали ошибку. А единый стандарт позволил новым сотрудникам быстрее включаться в работу и меньше переживать из-за частых возвратов кода от QA.
Александр Литвинов, бэкенд-разработчик в SpaceWeb: «Было полезно узнать ещё на старте работы, что часть возможных проблем с безопасностью уже решена настройками проекта или его архитектурой. Например, отключена поддержка xinclude для безопасной работы с XML, запрещены внешние allow_url_include в php.ini, чтобы нельзя было подключить внешние скрипты. Помимо этого мы разбирали и неочевидные для меня моменты в веб-безопасности — например, я не знал о возможности инъекции в PHP при использовании функции unserialize». |
Что получилось в итоге:
Новые сотрудники обучаются быстрее: вместо того, чтобы изучать многостраничные документы или проходить курсы, они получают краткую выжимку — только самое важное.
Руководитель тратит меньше времени на координацию взаимодействия между разработчиками и QA и разбор проблем. Каждая задача проходит несколько этапов: новая, в разработке, готова к тестированию, протестирована. Если нашли баг, задача возвращается в разработку. Когда изменился подход, таких «возвратов» стало меньше.
Компания тоже в плюсе: благодаря тому, что задачи закрываются быстрее, сотрудники могут сделать больше за то же время. При этом и качество кода после внедрения стандартов значительно выросло.
А как работа с веб-безопасностью устроена в вашей компании? Делитесь опытом в комментариях.