Оборонительное программирование

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

Какой минимальный уровень качества вы всегда будете применять к своему коду?

Ответ 1

В моей работе наш код должен быть высокого качества.
Итак, мы фокусируемся на двух основных вещах:

  • Тестирование
  • Обзор кода

Те приносят домой деньги.

Ответ 2

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

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

Ответ 3

Я бы рекомендовал защищать данные, которые вводят "компонент" или фреймворк. В рамках "компонента" или структуры следует думать, что данные "правильные".

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

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

Если в вызове есть ошибка, и в вызове используется неправильное значение. Что действительно нужно делать? У одного есть только указание на то, что "данные", над которыми работает программа, ошибочны, а некоторые вроде ASSERTS, а другие хотят использовать расширенные отчеты об ошибках и возможное восстановление ошибок. В любом случае данные оказались ошибочными, и в некоторых случаях полезно продолжить работу над ним. (учтите, что хорошо, если серверы не умрут как минимум)

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

Ответ 4

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

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

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

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

inline const Vector3 Normalize( Vector3arg vec )
{
    const float len = Length(vec);
    ASSERTMSG(len > 0.0f "Invalid Normalization");
    return len == 0.0f ? vec : vec / len;
}

Ответ 5

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

Ответ 6

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

Другие вещи, такие как хеширующие пароли, шифрование строк подключения и т.д., также являются стандартными.

Здесь, это зависит от фактического приложения.

К счастью, если вы работаете с такими фреймворками, как .Net, много встроенных средств защиты.

Ответ 7

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

Ответ 8

Использование Test Driven Development, безусловно, помогает. Вы пишете один компонент за раз, а затем перечисляете все потенциальные случаи ввода (через тесты) перед написанием кода. Это гарантирует, что вы охватили все базы и не указали какой-либо классный код, который никто не будет использовать, но может сломаться.

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

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

Ответ 9

Это зависит.

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

Чем скорее код будет использоваться, тем не менее, я увеличиваю уровень проверок.

  • минимальные магические числа
  • лучшие имена переменных
  • полностью проверенные и определенные длины массива/строки
  • программирование по договорным утверждениям
  • проверка значения null
  • исключения (в зависимости от контекста кода)
  • основные пояснительные комментарии
  • доступная документация по использованию (если perl и т.д.)

Ответ 10

Я возьму другое определение защитного программирования, которое будет одобрено Эффективная Java Джоша Блоха. В книге он рассказывает о том, как обрабатывать изменяемые объекты, которые вызывающие передают вашему коду (например, в сеттерах), и изменяемые объекты, которые вы передаете вызывающим абонентам (например, в геттерах).

  • Для сеттеров обязательно клонируйте любые изменяемые объекты и сохраните клон. Таким образом, вызывающие абоненты не могут изменить переданный объект после факта, чтобы разорвать ваши программные инварианты.
  • Для getters возвратите неизменяемое представление ваших внутренних данных, если интерфейс позволяет это; или вернуть клон внутренних данных.
  • При вызове вызываемых пользователем обратных вызовов с внутренними данными отправьте неизменяемое представление или клон, если это необходимо, если вы не намереваетесь выполнить обратный вызов для изменения данных, и в этом случае вам необходимо проверить его после факта.

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

Ответ 11

Я очень полагаю, что правильное программирование защитит эти риски. Такие вещи, как отказ от устаревших функций, которые (по крайней мере, в библиотеках Microsoft С++) обычно не рекомендуются из-за уязвимостей безопасности и проверяют все, что пересекает внешнюю границу.

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

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

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

Ответ 12

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

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

Ответ 13

Java, подписанные JAR и JAAS.

Java для предотвращения переполнения буфера и эксплойтов с использованием указателей/стека.

Не используйте JNI. (Java Native Interface) он предоставляет вам библиотеки DLL/Shared.

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

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

J2EE имеет (по общему признанию, ограниченную) встроенную поддержку безопасности на основе ролей.

Для некоторых из них есть некоторые накладные расходы, но дыры в безопасности уходят.

Ответ 14

Простой ответ: Это зависит от. Слишком много защитного кодирования может вызвать серьезные проблемы с производительностью.