Безопасность Ruby
Язык программирования Ruby большой и сложный, и начинающие, и опытные разработчики Ruby часто сталкиваются с множеством проблем безопасности.
В этом документе мы рассмотрим многие из этих проблем и предложим более безопасные альтернативы, где это возможно.
Полный список известных уязвимостей CVEs и как правильно сообщать о проблемах безопасности см. на сайте: 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 имеет явный получатель.
Например, следующий фрагмент кода выводит «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–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.