Процессы безопасной разработки - Академия Selectel

Процессы безопасной разработки

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

Изображение записи

Данный курс основан на материалах курса Developing Secure Software, разработанного объединением Open Source Security Foundation (OpenSSF), и рассматривает базовые вопросы, связанные с проектированием ПО, написанием безопасного кода, управлением уязвимостями, а также с использованием специализированных практик и инструментов при разработке ПО.

Основные процессы разработки

В разработке ПО есть процессы, в которые вовлечен каждый разработчик: проектирование, написание кода, тестирование и развертывание программы.

Проектирование включает в себя:

  • определение требований — что должно делать ПО. В случае с безопасностью убедитесь, что вы знаете, какие требования необходимо предусмотреть;
  • определение архитектуры — как разделить проблему на взаимодействующие компоненты для ее решения;
  • выбор компонентов многократного использования. Необходимо оценить компоненты — пакеты или библиотеки, которые вы будете использовать, поскольку любые их уязвимости могут стать уязвимостями ПО. Эти повторно используемые компоненты берутся откуда-то и транзитивно зависят от других компонентов. Совокупность всех этих зависимостей, включая то, откуда они берутся и как в итоге попадают к вам, и есть ваша цепочка поставок;

Реализация — написание кода. Большинство уязвимостей, возникающих в процессе реализации, относятся к конкретным распространенным типам. Зная их, вы сможете избежать ошибок.

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

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

Распространенная ошибка — пытаться выполнять процессы разработки ПО строго последовательно: сначала собрать все требования, затем спроектировать систему, потом целиком ее реализовать и только после этого протестировать. Этот подход называется водопадной моделью и поначалу кажется разумным. Но на практике жесткая последовательность почти всегда приводит к проблемам, и ее следует избегать.

Еще одна распространенная ошибка — реализовывать программные компоненты независимо друг от друга, не интегрировать и не тестировать их вместе. Обычно это приводит к серьезным проблемам с их совместной работой.

На практике описанные процессы обычно выполняются параллельно. Существует много подходов к организации разработки — например, гибкий (Agile), инкрементный и эволюционный. Выбор модели зависит от разных факторов: размера команды, требований к надежности. В этом курсе мы сосредоточимся на безопасности в разрезе отдельных процессов. Это позволит вам применять материалы независимо от того, какую модель разработки вы используете.

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

Настоятельно рекомендую использовать непрерывную интеграцию (Continuous Integration, CI). Это регулярное слияние рабочих копий разработчиков в общую ветку до нескольких раз в день. Такой подход снижает риск того, что компоненты перестанут работать вместе, если интеграцию откладывать на потом.

Однако для успешной CI нужно проверять, действительно ли компоненты работают вместе. Это решается с помощью конвейера CI — автоматизированного процесса, который запускается при каждом слиянии. Он проверяет, собирается ли код и проходит ли он набор тестов и других проверок.

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

Непрерывная доставка (Continuous Delivery, CD или CDE).Практика, направленная на то, чтобы приложение всегда было готово к запуску после успешного прохождения автоматизированных тестов и проверок качества. Это достигается путем автоматической доставки ПО в среду, аналогичную производственной. Обратите внимание: хотя ПО может быть автоматически доставлено в среду, подобную производственной, это не означает, что оно обязательно развертывается без отдельного этапа утверждения.
Непрерывное развертывание (Continuous Deployment, CD). Непрерывное развертывание идет на шаг дальше, чем непрерывная доставка, и автоматически и непрерывно развертывает приложение в производственной среде.

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

GitOps.Практики GitOps помогают в непрерывном развертывании cloud-native приложений. Они ориентированы на процессы эксплуатации инфраструктуры и используют уже знакомые разработчикам инструменты, включая Git и инструменты непрерывного развертывания. Основная идея GitOps — наличие Git-репозитория, который содержит декларативные описания инфраструктуры в том виде, в котором она должна быть в производственной среде в данный момент. Автоматизированный процесс приводит реальную среду в соответствие с состоянием, описанным в репозитории. Чтобы развернуть новое приложение или обновить существующее, достаточно изменить инфраструктурный код в Git — все остальное сделают инструменты автоматизации.

С точки зрения безопасности важно, чтобы наряду с инструментами для тестирования качества ПО в автоматизированные процессы CI/CD были интегрированы инструменты для проверки уязвимостей и потенциальных проблем безопасности. Инструменты безопасности обычно работают долго, поэтому их можно запускать параллельно с другими инструментами. Но если они обнаруживают серьезные недостатки, их результаты должны использоваться для остановки CI/CD.

Само по себе добавление инструментов безопасности в конвейер CI/CD, как правило, неэффективно. Инструменты не знают, какие требования предъявляются к ПО и как оно правильно должно работать. Также они не могут обнаружить фундаментальные проблемы в архитектуре программ. Вам необходимо анализировать результаты работы, чтобы использовать выводы для непрерывного совершенствования как самого ПО, так и процессов его разработки.

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

Управление рисками

При создании сервиса важно учитывать риски как для пользователя, так и для провайдера. Когда программа станет доступна другим людям, найдется тот, кто попытается атаковать уязвимые места.

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

Хотя полностью защитить ПО от атак невозможно, можно управлять рисками: усложнить атаку или уменьшить ее последствия. Но не стоит ждать, пока риски превратятся в реальные проблемы. Разработать ПО с учетом угроз гораздо проще и дешевле, чем устранять последствия атаки и вносить срочные изменения в ПО сервиса, уже доступного пользователям.

В своем эссе «Процесс безопасности» (The Process of Security, 2000) Брюс Шнайер отметил, что безопасность не обязательно должна быть совершенной, но риски должны быть управляемыми.

Процесс управления рисками включает три этапа.

  • Идентификация. Определите, что может пойти не так. Полезно изучить похожие проекты и посмотреть, с какими проблемами они сталкивались. Составьте список таких рисков, уделяя особое внимание аспектам безопасности. 
  • Анализ. Оцените два ключевых атрибута каждого риска: возможность наступления нежелательного события и серьезность его последствий. Риск считается более значимым, если его вероятность и уровень воздействия увеличиваются. 
  • Обработка. Определите, что вы будете делать с рисками. Есть несколько вариантов: принятие, избегание, передача и контроль.

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

При избегании риск устраняется с внесением изменений в требования к ПО. Это лучший вариант, если он возможен. Например, вы можете отказаться от сбора некоторых данных или выбрать язык программирования, на котором не могут возникнуть определенные виды уязвимостей. 

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

А в случае контроля компания стремится снизить риски до приемлемого уровня. Единого способа сделать это не существует, поэтому вам придется вносить изменения в ПО, пока уровень рисков не станет приемлемым. Например, вы можете:

  • убедиться, что все разработчики знают об определенных видах распространенных ошибок, которые приводят к уязвимости;
  • использовать специальные языки программирования и API, которые призваны снизить вероятность возникновения уязвимостей;
  • использовать инструменты выявления ошибок;
  • изменить ПО таким образом, чтобы его возможные недостатки с меньшей вероятностью стали уязвимостями безопасности.

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

У Брюса Шнайера есть замечательная история (The Security Mindset, 2008):

Компания Uncle Milton Industries с 1956 года продает детям муравьиные фермы. Несколько лет назад мы с другом открыли одну такую ферму. В коробке не было настоящих муравьев, вместо этого лежала карточка, на которой нужно было указать свой адрес. Компания обещала выслать муравьев по почте. Мой друг удивился, что муравьев могут отправить по почте. Брюс Шнайер сказал: ”Интересно, что эти люди отправят тюбик с живыми муравьями любому, кому вы скажете”. Безопасность требует особого мышления. Хорошие специалисты по безопасности видят мир по-другому. Они не могут зайти в магазин и не обратить внимания на возможность кражи. Они не могут пользоваться компьютером, не думая об уязвимостях в системе безопасности. Они не могут голосовать, не пытаясь понять, как можно проголосовать дважды.



Можно ли научить такому мышлению? Опыт показывает, что да. Контрольные списки, инструкции и советы напоминают людям о необходимости искать определенные паттерны, особенно если они основаны на соответствующем прошлом опыте. 

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

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

Этот курс предлагает несколько советов, которые помогут снизить уровень рисков. Однако эти советы — лишь помощь; важно самостоятельно думать о безопасности. Разрабатывая ПО, рассуждайте, как те или иные его особенности могут быть использованы для обхода механизмов безопасности и выполнения определенных действий с данными совсем не так, как вы это задумывали.