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

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

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

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

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

Безопасное программирование

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

int рискованное_программирование(char *ввод){  char ул[1000];     // ...    strcpy(ул, ввод);  // Копируем input.    // ...}

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

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

Наступательное программирование

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

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

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

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

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

Методы

Вот несколько приемов защитного программирования:

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

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

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

Проблемы с наследием

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

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

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

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

Известные примеры устаревшей проблемы:

  • BIND 9, представленный Полом Викси и Дэвидом Конрадом как "BINDv9 - это полностью переписать "," Безопасность была ключевым фактором при проектировании ",[1] называя безопасность, надежность, масштабируемость и новые протоколы ключевыми проблемами при переписывании старого устаревшего кода.
  • Майкрософт Виндоус пострадал от " Уязвимость метафайла Windows и другие эксплойты, связанные с форматом WMF. Центр поддержки безопасности Microsoft описывает функции WMF как «Примерно в 1990 году была добавлена ​​поддержка WMF ... Это было другое время в сфере безопасности ... всем полностью доверяли»,[2] не разрабатывается в рамках инициатив по безопасности в Microsoft.
  • Oracle борется с унаследованными проблемами, такими как старый исходный код, написанный без решения проблем SQL-инъекция и повышение привилегий, что привело к появлению множества уязвимостей в системе безопасности, на исправление которых потребовалось время, а также к появлению неполных исправлений. Это вызвало резкую критику со стороны таких экспертов по безопасности, как Дэвид Литчфилд, Александр Корнбруст, Сезар Черрудо.[3][4][5] Дополнительная критика заключается в том, что установки по умолчанию (в основном унаследованные от старых версий) не соответствуют их собственным рекомендациям по безопасности, таким как Контрольный список безопасности базы данных Oracle, который сложно изменить, поскольку для правильной работы многим приложениям требуются менее безопасные устаревшие настройки.

Канонизация

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

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

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

Другие техники

  • Одна из наиболее распространенных проблем - неконтролируемое использование структур и функций постоянного размера для данных динамического размера ( переполнение буфера проблема). Это особенно характерно для строка данные в C. Функции библиотеки C, такие как получает никогда не следует использовать, поскольку максимальный размер входного буфера не передается в качестве аргумента. Функции библиотеки C, такие как сканф можно безопасно использовать, но требуется, чтобы программист позаботился о выборе строк безопасного формата, очистив их перед использованием.
  • Шифрование / аутентификация всех важных данных, передаваемых по сетям. Не пытайтесь реализовать свою собственную схему шифрования, а используйте вместо нее проверенную.
  • Все данные важно, пока не будет доказано обратное.
  • Все данные испорчены, пока не будет доказано обратное.
  • Весь код небезопасен, пока не будет доказано обратное.
  • Если необходимо проверить данные на правильность, убедитесь, что они верны, а не неверны.
  • Дизайн по контракту
    • Дизайн по контракту использует предварительные условия, постусловия и инварианты чтобы гарантировать, что предоставленные данные (и состояние программы в целом) очищены. Это позволяет коду документировать свои предположения и безопасно их делать. Это может включать проверку аргументов функции или метода на предмет допустимости перед выполнением тела функции. После тела функции также целесообразно выполнить проверку состояния или других хранимых данных и возвращаемого значения перед выходом (код прерывания / возврата / выброса / ошибки).
  • Утверждения (также называется напористое программирование)
    • Внутри функций вы можете проверить, что вы не ссылаетесь на что-то недопустимое (то есть на null) и что длины массивов действительны до ссылки на элементы, особенно во всех временных / локальных экземплярах. Хорошая эвристика - не доверять библиотекам, которые вы тоже не писали. Поэтому каждый раз, когда вы им звоните, проверяйте, что вы от них получите. Часто помогает создать небольшую библиотеку функций «утверждения» и «проверки», чтобы сделать это вместе с регистратором, чтобы вы могли отслеживать свой путь и уменьшить потребность в обширных отладка циклы в первую очередь. С появлением библиотек логирования и аспектно-ориентированное программирование, многие из утомительных аспектов защитного программирования смягчаются.
  • Предпочитаю исключения вернуть коды
    • Вообще говоря, предпочтительнее генерировать понятные сообщения об исключениях, которые обеспечивают выполнение части вашего API заключить договор и направить клиента программист вместо того, чтобы возвращать значения, к которым программист-клиент, вероятно, не будет подготовлен, и, следовательно, минимизировать их жалобы и повысить надежность и безопасность вашего программного обеспечения.[сомнительный ]

Смотрите также

использованная литература

  1. ^ "Архив fogo: Пол Викси и Дэвид Конрад о BINDv9 и безопасности в Интернете, автор Джеральд Оскобойни ". amazing.net. Получено 2018-10-27.
  2. ^ «Глядя на проблему WMF, как она туда попала?». MSRC. Архивировано из оригинал на 2006-03-24. Получено 2018-10-27.
  3. ^ Литчфилд, Дэвид. "Bugtraq: Oracle, где патчи ???". seclists.org. Получено 2018-10-27.
  4. ^ Александр, Корнбруст. "Bugtraq: RE: Oracle, где патчи ???". seclists.org. Получено 2018-10-27.
  5. ^ Серрудо, Сезар. "Bugtraq: Re: [Полное раскрытие] RE: Oracle, где патчи ???". seclists.org. Получено 2018-10-27.

внешние ссылки