Spec-Zone.ru › Ruby 2.6

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

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

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

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

Начиная с версии 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–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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