Spec-Zone.ru › Ruby 2.2

Безопасность Ruby

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

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

Пожалуйста, ознакомьтесь с полным списком общеизвестных CVE и тем, как правильно сообщать об уязвимости безопасности по адресу: www.ruby-lang.org/en/security/ Версия для японского языка находится здесь: www.ruby-lang.org/ja/security/

Уязвимости безопасности необходимо сообщать по электронной почте на адрес security@ruby-lang.org (открытый ключ PGP), который является закрытым списком рассылки. Сообщённые проблемы будут опубликованы после исправления.

$SAFE

Ruby предоставляет механизм для ограничения операций, которые может выполнять код Ruby, в виде переменной $SAFE.

Однако, $SAFE не обеспечивает безопасную среду для выполнения кода из недоверенного источника.

Если вам нужно выполнить недоверенный код, вы должны использовать механизм изоляции на уровне операционной системы. В Linux можно использовать ptrace или LXC для изоляции потенциально вредоносного кода. Аналогичные механизмы существуют во всех основных операционных системах.

Marshal.load

Модуль Marshal Ruby предоставляет методы для сериализации и десериализации деревьев объектов Ruby в двоичный формат данных и обратно.

Никогда не используйте Marshal.load для десериализации недоверенных или предоставленных пользователем данных. Так как Marshal может десериализовать практически любой объект Ruby и имеет полный контроль над переменными экземпляра, возможно создание вредоносной загрузки, выполняющей код сразу после десериализации.

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

YAML

YAML — популярный удобочитаемый формат сериализации данных, используемый во многих программах Ruby для конфигурации и сохранения деревьев объектов Ruby в базах данных.

Аналогично Marshal, он может десериализовывать произвольные классы Ruby. Например, следующие данные YAML создадут объект ERB при десериализации:

!ruby/object:ERB
src: puts `uname`

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

Символы

Символы часто рассматриваются как синтаксический сахар для простых строк, но они играют гораздо более важную роль. Реализация MRI Ruby использует символы внутри для имен методов, переменных и констант. Причина в том, что символы — это просто целые числа с прикреплёнными к ним именами, поэтому их быстрее искать в хеш-таблицах.

После создания символа используемая им память никогда не освобождается. Если вы преобразуете пользовательский ввод в символы с помощью to_sym или intern, злоумышленник может организовать атаку типа «отказ в обслуживании» вашей программе, завалив её уникальными строками. Поскольку каждая строка хранится в памяти до выхода процесса Ruby, это приведёт к постоянно растущему потреблению памяти, пока Ruby не исчерпает память и не аварийно завершит работу.

Будьте осторожны при передаче пользовательского ввода в методы, такие как send, instance_variable_get или _set, const_get или _set, и т.д., так как эти методы преобразуют строковые параметры во внутренние символы и представляют ту же угрозу «отказа в обслуживании», что и непосредственное преобразование через to_sym/intern.

Решение этой проблемы простое — не преобразуйте пользовательский ввод в символы. Постарайтесь оставить пользовательский ввод в строковом формате.

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

Синтаксис регулярных выражений Ruby имеет некоторые незначительные отличия от других языков. В Ruby якоря ^ и $ не относятся к началу и концу строки, а к началу и концу строки.

Это означает, что если вы используете регулярное выражение, например, /^[a-z]+$/ для ограничения строки только буквами, злоумышленник может обойти эту проверку, передав строку, содержащую букву, затем новую строку, а затем любую строку по своему выбору.

Если вы хотите сопоставить начало и конец всей строки в Ruby, используйте якоря \A и \z.

eval

Никогда не передавайте недоверенный или контролируемый пользователем ввод в eval.

Если вы не реализуете интерактивную оболочку, такую как irb или pry, eval почти наверняка не то, что вам нужно. Не пытайтесь отфильтровать пользовательский ввод перед передачей его в eval — этот подход сопряжён с опасностью и, скорее всего, откроет вашу программу для серьёзной уязвимости удалённого выполнения кода.

send

«Глобальные функции» в Ruby (puts, exit, и т.д.) фактически являются частными методами экземпляров Object. Это означает, что вы можете вызвать эти методы с помощью send, даже если вызов send имеет явный получатель.

Например, следующий фрагмент кода выводит «Hello world» в терминал:

1.send(:puts, "Hello world")

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

foo.send(params[:bar]) # params[:bar] is "exit!"

Если злоумышленник может контролировать первые два аргумента send, возможно удалённое выполнение кода:

# params is { :a => "eval", :b => "...ruby code to be executed..." }
foo.send(params[:a], params[:b])

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

Обратите внимание, что использование public_send также опасно, так как send само по себе является общедоступным:

1.public_send("send", "eval", "...ruby code to be executed...")

DRb

Так как DRb позволяет удалённым клиентам вызывать произвольные методы, его не следует предоставлять недоверенным клиентам.

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

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API