Мы все знаем принцип, что «Безопасность — это ответственность каждого», но как инженеры-программисты могут участвовать и учитывать безопасность?

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

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

Проект Open Web Application Security Project (OWASP) создал OWASP TOP 10 Proactive Controls Project (OPC) для поощрения разработчиков, начинающих с безопасности приложений. Эта запись в блоге обобщает ее содержание, а также добавляет к ней подсказки и информацию. Пожалуйста, имейте в виду, что это должно только повысить осведомленность и является отправной точкой для более глубокого изучения этой темы.

Определите требования безопасности

Безопасность подпадает под категорию нефункциональных требований. Он должен определять необходимые функции безопасности, которым должно удовлетворять программное обеспечение. Чтобы сэкономить время и не изобретать велосипед на каждом новом проекте, вы можете выбрать требования безопасности из каталога. Существует общий под названием Стандарт проверки безопасности приложений (ASVS) и один для мобильных устройств под названием Стандарт проверки мобильных приложений (MASVS). Они содержат набор требований, которые являются передовой практикой для каждой из перечисленных категорий. К счастью, они сопоставили эти требования с CWE (общее перечисление слабостей, которое в основном представляет собой список слабостей программного и аппаратного обеспечения). В зависимости от используемых инструментов эти CWE могут автоматически сканироваться в вашем коде.

Использование фреймворков и библиотек безопасности

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

Безопасный доступ к базе данных

Здесь есть несколько подпунктов, но мы пройдемся по ним довольно быстро. Защитите свои запросы. Мы все знаем эти забавные шутки с SQL-инъекциями, но вы можете легко решить эту проблему с помощью параметризации запросов. Вы можете найти шпаргалку от OWASP здесь и другую от Bobby Tables здесь.
Системы управления базами данных не всегда настроены безопасно по умолчанию. Доступны рекомендации и эталонные тесты, с которыми вы можете ознакомиться, например, здесь.
Доступ к базе данных должен быть надлежащим образом аутентифицирован. Это должно происходить по безопасному каналу, и ваши учетные данные должны быть надежно защищены. Помимо аутентификации с помощью учетных данных, вам также следует проверить, можно ли получить к нему доступ с помощью управляемого удостоверения.
Последний пункт — это безопасная связь. Шифрование ваших данных при передаче за счет обеспечения сквозной безопасности связи при передаче конфиденциальных данных по любой сети. Это можно сделать через TLS. Там есть руководства, помогающие выбрать минимально допустимую версию TLS и выбрать набор шифров.

Кодировать и экранировать данные

И здесь мы снова достигаем инъекционных атак. Кодируя символы, мы гарантируем, что специальные символы не будут обрабатываться со злым умыслом. Это означает, что содержимое будет отображаться, но не выполняться. Например, вместо отправки ‹script› мы кодируем специальные символы, введенные пользователем, и отправляем script, который будет отображаться в браузере как ‹script›, но выполняться не будет. Эта выходная кодировка должна применяться до того, как содержимое будет передано целевому интерпретатору, для защиты от XSS. Есть несколько примеров для C#, Java и PHP. Существуют также другие типы защиты от кодирования и внедрения, такие как экранирование оболочки для ввода команды ОС. Формы побега не ограничиваются перечисленными здесь примерами. Ознакомьтесь с рекомендациями и рекомендациями по использованию пользовательского ввода для определенных операций.

Подтвердить все входные данные

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

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

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

Как правило, существует два подхода к проверке синтаксиса: занесение в черный список и занесение в белый список. В то время как черный список блокирует точные тексты (например, «‹script›») для предотвращения инъекций, белый список проверяет совпадения наборов данных. Как правило, рекомендуется использовать белый список в минимальном количестве вместо черного списка, поскольку он подвержен обходным действиям. Другими словами, белый список ограничивает поверхность атаки, а черный список выявляет и останавливает очевидные атаки.
Имейте в виду, что эти проверки имеют ограничения. Поскольку сложность допускает больше вариаций и возможностей, действительные данные все еще не могут быть опасными.

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

Существует множество библиотек проверки, которые можно использовать для проверки данных. В PHP есть функции фильтрации, в Java — Hibernate Validator, а в C# — FluentValidation. Вы также можете очистить свои данные, чтобы удалить ненужные данные при вводе. Имейте в виду, что проверка ввода не должна быть вашим основным методом предотвращения инъекций и других атак.

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

Помимо сериализованных данных, есть еще проблема с автопривязкой. Некоторые платформы поддерживают автоматическую привязку параметров HTTP-запроса к объектам на стороне сервера, потребляемым приложением. Эти привязки позволяют вектору атаки использовать уязвимость под названием Массовое присвоение. Например, пользователь может установить для параметра isAdmin значение true, чтобы повысить привилегии. Есть два способа справиться с этим: либо избежать автоматической привязки и использовать объекты передачи данных (TDO), которые в основном являются POCO, либо настроить правила белого списка, чтобы определить, какие поля могут быть автоматически привязаны. Существует шпаргалка от OWASP, которую вы можете посмотреть здесь, чтобы получить больше информации о том, как решить эту проблему.

Обеспечение контроля доступа

Контроль доступа управляет доступом к системам, а также к ресурсам и гарантирует, что доступ имеют только авторизованные пользователи/системы. Необходимо заставить все запросы проходить контроль доступа, чтобы убедиться, что каждый запрос проверен и авторизован для прохождения. Возможно, вы уже встречались с терминами привилегия, право и разрешение. Это не взаимозаменяемые термины! Для получения дополнительной информации прочитайте статью Wentz Wus.

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

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

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

Вместо этого вы должны реализовать права и проверить их.

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

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

Защита данных

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

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

Секреты приложений никогда не должны храниться в коде, конфигах или других файлах. Храните их в секретном хранилище, таком как Azure KeyVault или Amazon KMS. Помимо безопасности, это также дает больше гибкости при настройке вашего решения.

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

Внедрение ведения журнала безопасности и мониторинга

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

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

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

  • Представленные данные, выходящие за пределы ожидаемого диапазона
  • Представленные данные, содержащие изменения, которые нельзя изменить
  • Запросы, нарушающие правила контроля доступа

Более полный список можно найти на вкладке OWASP AppSensor Detection_points здесь.
При обнаружении таких действий приложение должно реагировать на возможные атаки и отключать их.

Также есть небольшая шпаргалка, связанная с логированием безопасности приложений здесь.

Обработка всех ошибок и исключений

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

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

Чтобы помочь обнаружить возможные сбои на ранней стадии, вы также можете использовать Chaos Monkey от Netflix. Он случайным образом завершает виртуальные машины и контейнеры, чтобы показать, насколько устойчивы ваши сервисы.

Еще немного информации

Обзор кода

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

Не пишите собственное шифрование

У некоторых разработчиков возникает соблазн внедрить собственное шифрование. Закон Шнейра гласит

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

Поскольку эти люди считают, что не могут взломать свой шифр, они используют его как доказательство того, что его невозможно взломать. Это хороший пример эффекта Даннинга-Крюгера. Существует дискуссия о том, почему не рекомендуется писать собственное шифрование на Stack Exchange.
Поэтому используйте существующие решения, признанные в отрасли, и следуйте их лучшим практикам.