Защитное программирование

редактировать

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

Защитное программирование - это подход к улучшению программного обеспечения и исходного кода с точки зрения:

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

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

Содержание
  • 1 Безопасное программирование
  • 2 Наступательное программирование
    • 2.1 Доверие внутренней достоверности данных
    • 2.2 Доверие программным компонентам
  • 3 Методы
    • 3.1 Интеллектуальное повторное использование исходного кода
      • 3.1.1 Унаследованные проблемы
    • 3.2 Канонизация
    • 3.3 Низкая устойчивость к «потенциальным» ошибкам
    • 3.4 Другие методы
  • 4 См. Также
  • 5 Ссылки
  • 6 Внешние ссылки
Безопасное программирование

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

int risky_programming (char * input) {char str [1000]; //... strcpy (str, input); // Копируем input. //...}

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

int secure_programming (char * input) {char str [1000 + 1]; // Еще один для нулевого символа. //... // Копируем ввод, не превышая длины адресата. strncpy (str, input, sizeof (str)); // Если strlen (input)>= sizeof (str), тогда strncpy не будет завершаться нулём. // Мы противодействуем этому, всегда устанавливая последний символ в буфере на NUL, // эффективно обрезая строку до максимальной длины, которую мы можем обработать. // Также можно решить явно прервать выполнение программы, если // strlen (input) слишком длинный. str [sizeof (str) - 1] = '\ 0'; //...}
Наступательное программирование

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

Доверять внутренним данным

Чрезмерно защитное программирование
const char * trafficlight_colorname (enum traffic_light_color c) {переключатель (c) {case TRAFFICLIGHT_RED: вернуть "красный"; case TRAFFICLIGHT_YELLOW: вернуть «желтый»; case TRAFFICLIGHT_GREEN: вернуть «зеленый»; } return «черный»; // Считаться мертвым светофором. }
Оскорбительное программирование
const char * trafficlight_colorname (enum traffic_light_color c) {switch (c) {case TRAFFICLIGHT_RED: return "red"; case TRAFFICLIGHT_YELLOW: вернуть «желтый»; case TRAFFICLIGHT_GREEN: вернуть «зеленый»; } assert (0); // Утверждаем, что этот раздел недоступен. }

Доверие программным компонентам

Чрезмерно защитное программирование
if (is_legacy_compatible (user_config)) {// Стратегия: не верьте, что новый код ведет себя так же, как old_code (user_config); } else {// Резерв: не верьте, что новый код обрабатывает те же случаи if (new_code (user_config)! = OK) {old_code (user_config); }}
Оскорбительное программирование
// Доверяйте, что в новом коде нет новых ошибок new_code (user_config);
Методы

Вот некоторые методы защитного программирования:

Интеллектуальное повторное использование исходного кода

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

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

Проблемы прежних версий

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

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

Многие программные продукты столкнулись с проблемами со старым унаследованным исходным кодом, например:

  • Устаревший код, возможно, не был разработан в рамках инициативы защитного программирования и, следовательно, может иметь гораздо более низкое качество, чем новый. разработанный исходный код.
  • Устаревший код мог быть написан и протестирован в условиях, которые больше не применяются. Старые тесты по обеспечению качества могут больше не иметь силы.
    • Пример 1 : унаследованный код мог быть разработан для ввода ASCII, но теперь вводом является UTF-8.
    • Пример 2 : унаследованный код мог быть скомпилирован и протестирован на 32-битных архитектурах, но при компиляции на 64-битных архитектурах могут возникнуть новые арифметические проблемы (например, неверные тесты подписи, недопустимое приведение типов и т. д.).
    • Пример 3 : унаследованный код мог быть предназначен для автономных машин, но однажды становится уязвимым добавлено подключение к сети.
  • Устаревший код не написан с учетом новых проблем. Например, исходный код, написанный около 1990 года, вероятно, будет подвержен множеству уязвимостей внедрения кода, потому что большинство таких проблем в то время не было широко изучено.

Примечательные примеры устаревшей проблемы:

  • BIND 9, представленный Полом Викси и Дэвидом Конрадом как «BINDv9 - это полная переработка », «Безопасность была ключевым фактором при разработке», называя безопасность, надежность, масштабируемость и новые протоколы в качестве ключевых проблем для перезаписи старого устаревшего кода.
  • Microsoft Windows страдала от «» уязвимости метафайла Windows и других эксплойтов, связанных с форматом WMF. Центр Microsoft Security Response Center описывает функции WMF следующим образом: «Примерно в 1990 году была добавлена ​​поддержка WMF... Это было другое время в сфере безопасности... всем полностью доверяли», а не разрабатывались в рамках инициатив по безопасности в Microsoft.
  • Oracle борется с устаревшими проблемами, такими как старый исходный код, написанный без решения проблем SQL-инъекций и повышения привилегий, что приводит к появлению многих уязвимостей безопасности, на исправление которых потребовалось время а также сгенерированы неполные исправления. Это вызвало резкую критику со стороны таких экспертов по безопасности, как Дэвид Литчфилд,. Дополнительная критика заключается в том, что установки по умолчанию (в основном унаследованные от старых версий) не согласованы с их собственными рекомендациями по безопасности, такими как Контрольный список безопасности базы данных Oracle, который трудно исправить, поскольку многие приложения требуют менее безопасного устаревшего настройки для правильной работы.

Канонизация

Злоумышленники могут изобретать новые виды представления неверных данных. Например, если программа пытается отклонить доступ к файлу «/ etc / passwd », взломщик может передать другой вариант этого имени файла, например «/etc/./passwd». Библиотеки канонизации могут использоваться, чтобы избежать ошибок из-за неканонического ввода .

Низкая устойчивость к «потенциальным» ошибкам

Предположим, что конструкции кода, которые кажутся склонными к проблемам (аналогично известным уязвимостям и т. Д.), Являются ошибками и потенциальными недостатками безопасности. Основное эмпирическое правило: «Я не знаю всех типов уязвимостей безопасности. Я должен защищаться от тех, о которых я знаю, и тогда я должен действовать упреждающе!».

Другие методы

  • Одна из наиболее распространенных проблем - это неконтролируемое использование структур и функций постоянного размера для данных динамического размера (проблема переполнения буфера ). Это особенно характерно для данных string в C. Функции библиотеки C, такие как gets, никогда не должны использоваться, поскольку максимальный размер входного буфера не передается в качестве аргумента. Функции библиотеки C, такие как scanf, могут использоваться безопасно, но требуют, чтобы программист позаботился о выборе строк безопасного формата, очистив их перед использованием.
  • Шифрование / аутентификация всех важных данных передается по сетям. Не пытайтесь реализовать свою собственную схему шифрования, вместо этого используйте проверенную.
  • Все данные важны, пока не доказано обратное.
  • Все данные испорчены, пока не будет доказано обратное..
  • Весь код небезопасен, пока не будет доказано обратное.
    • Вы не можете доказать безопасность какого-либо кода в пользовательской среде, или, более канонично: «никогда не доверяйте клиенту».
  • Если данные должны быть проверены на правильность, убедитесь, что они правильно, а не то, что это неверно.
  • Дизайн по контракту
    • Дизайн по контракту использует предварительные условия, постусловия и инварианты, чтобы гарантировать, что предоставленные данные (и состояние программы в целом) санировано. Это позволяет коду документировать свои предположения и безопасно их делать. Это может включать проверку аргументов функции или метода на предмет допустимости перед выполнением тела функции. После тела функции также целесообразно выполнить проверку состояния или других хранимых данных и возвращаемое значение перед выходом (код прерывания / возврата / выброса / ошибки).
  • Утверждения (также называемые напористое программирование )
    • Внутри функций вы можете проверить, что вы не ссылаетесь на что-то недопустимое (т. е. на null) и что длины массивов действительны перед ссылками на элементы, особенно во всех временных / локальных экземплярах. Хорошая эвристика заключается в том, чтобы не доверять библиотекам, которые вы тоже не писали. Поэтому всякий раз, когда вы вызываете их, проверяйте, что вы от них получаете. Часто помогает создать небольшую библиотеку функций «утверждения» и «проверки», чтобы сделать это вместе с logger, чтобы вы могли отслеживать свой путь и, в первую очередь, снизить потребность в обширных циклах отладки. С появлением библиотек журналирования и аспектно-ориентированного программирования многие утомительные аспекты защиты
  • Предпочитать исключения кодам возврата
    • Как правило Кроме того, предпочтительнее генерировать понятные сообщения об исключениях, которые обеспечивают выполнение части вашего API контракта и направляют клиента программиста вместо того, чтобы возвращать значения, к которым клиентский программист, вероятно, не будет подготовлен и, следовательно, свести к минимуму их жалобы и повысить надежность и безопасность вашего программного обеспечения.
См. также
Ссылки
  1. ^"fogo archive: Пол Викси и Дэвид Конрад о BINDv9 и Internet Security Геральда Оскобойного ". впечатляющий.net. Проверено 27 октября 2018 г.
  2. ^«Если посмотреть на проблему с WMF, как она туда попала?». MSRC. Архивировано с оригинального 24 марта 2006 г. Проверено 27 октября 2018 г.
  3. ^Личфилд, Дэвид. «Ошибка: Oracle, где патчи ???». seclists.org. Проверено 27 октября 2018.
  4. ^Александр, Корнбруст. «Ошибка: RE: Oracle, где патчи ???». seclists.org. Проверено 27 октября 2018.
  5. ^Cerrudo, Cesar. «Ошибка: Re: [Полное раскрытие] RE: Oracle, где патчи ???". seclists.org. Дата обращения 27.10.2018.
Внешние ссылки
Последняя правка сделана 2021-05-17 11:26:01
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте