Spec-Zone.ru › Ruby 3.2

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

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

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

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

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

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 использует символы во внутренней форме для имен методов, переменных и констант. Причина в том, что символы — это просто целые числа с присоединенными к ним именами, поэтому их быстрее искать в хэш-таблицах.

Начиная с версии 2.2, большинство символов могут быть собраны сборщиком мусора; они называются временными символами. Большинство создаваемых вами символов (например, вызывая to_sym) являются временными.

Бессмертные символы, с другой стороны, никогда не будут собраны сборщиком мусора. Они создаются при изменении кода:

  • определение метода (например, с помощью define_method),

  • установка переменной экземпляра (например, с помощью instance_variable_set),

  • создание переменной или константы (например, с помощью const_set)

Расширения C, которые не были обновлены и по-прежнему вызывают «SYM2ID», создают бессмертные символы. Ошибки в 2.2.0: send и __send__ также создавали бессмертные символы, а вызовы методов с ключевыми аргументами также могли создавать некоторые.

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

Хотя вызов этих методов с пользовательскими данными, вероятно, не является хорошей идеей, ранее уязвимые методы, такие как to_sym, respond_to?, method, instance_variable_get, const_get, и т. д., больше не представляют угрозы.

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

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

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

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

eval

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

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

send

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

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

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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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