C5: Обязательная проверка всех входных данных

Описание

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

Синтаксическая и семантическая норма

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

Синтаксическая норма означает соответствие данных ожидаемой форме представления. Например, в приложении пользователь может указывать четырехзначный «идентификатор» для выполнения некоторых операций. Злоумышленник может ввести данные, позволяющие ему внедрить SQL-код, поэтому приложение должно проверять, что вводимые данные представляют собой именно цифры и именно в количестве четырех символов (помимо использования соответствующей параметризации запросов).

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

Белые и черные списки

Существует два основных подхода к проверке синтаксиса входных данных, известные как черные и белые списки.

  • Черные списки или проверки по черному списку предназначены для поиска в данных «потенциально вредоносного» контента. Например, веб-приложение может блокировать входные данные, содержащие слово <SCRIPT>, с целью предотвращения межсайтового выполнения сценариев. Однако подобную меру защиты можно обойти, используя для тега script строчные буквы или комбинацию из строчных и прописных букв.
  • Белые списки или проверки по белому списку предназначены для подтверждения соответствия данных требованиям набора «проверенных» правил. Например, проверка штата США по белому списку будет представлять собой поиск 2-буквенного кода в списке существующих штатов США.

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

Проверки на стороне клиента и на стороне сервера

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

Регулярные выражения

Регулярные выражения позволяют проверять данные на соответствие определенному шаблону. Начнем с простого примера.

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

^[a-z0-9_]{3,16}$

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

Внимание! Возможен отказ в обслуживании

При создании регулярных выражений необходимо соблюдать осторожность. Плохо продуманные выражения могут привести к отказу в обслуживании (т. н. ReDoS — отказ в обслуживании из-за регулярных выражений). Для проверки регулярных выражений на ReDoS существует много разных инструментов.

Внимание! Сложность реализации

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

Ограничения проверок входных данных

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

Проблемы проверки сериализованных данных

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

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

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

Непредусмотренные входные данные (массовое назначение)

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

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

Простой пример: если объект пользователя имеет специальное поле «привилегия», определяющее уровень привилегий пользователя в приложении, то злоумышленник может найти страницы с измененными данными пользователя и добавить privilege=admin к отправленным HTTP-параметрам. При небезопасной настройке автопривязки серверный объект, представляющий пользователя, будет изменен соответствующим образом.

Решить данную проблему можно двумя способами:

  • избегать привязки входных данных напрямую и использовать вместо этого объекты переноса данных (DTO);
  • настроить белые списки для каждой страницы или функции, которые будут определять поля, разрешенные для автопривязки.

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

Проверка и очистка HTML

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

  • Регулярных выражений будет недостаточно, чтобы отобразить всю сложность HTML5.
  • Кодировка или экранирование HTML не подойдет, так как приведет к некорректному отображению HTML-кода.

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

Функции проверки в библиотеках и фреймворках

Все языки и большинство фреймворков имеют библиотеки или функции, которые рекомендуется использовать для проверки данных. Подобные библиотеки, как правило, обеспечивают проверку стандартных типов данных, требований к длине, диапазонов целых чисел, «нулевых данных» и т. п. Большинство библиотек и фреймворков позволяют создавать собственные регулярные выражения или логику проверок, позволяя программистам использовать данную функцию в приложениях. Примеры реализации функции проверки: функции фильтрации PHP или Hibernate Validator для Java. Примеры инструментов для очистки HTML: метод очистки Ruby on Rails, средство очистки HTML на Java от OWASP или DOMPurify.

Предотвращаемые уязвимости

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