Философия Ruby on Rails делает разработку простой и эффективной, так что неудивительно, что у фреймворка сформировалось огромное сообщество. Давай познакомимся поближе с философией этой платформы как с точки зрения архитектуры, так и с точки зрения безопасности.

 

«ВЕБ-РАЗРАБОТКА, КОТОРАЯ НЕ ПАРИТ»

2012–2013 годы стали черной полосой для Ruby on Rails в плане безопасности — проверке на прочность подвергся как сам фреймворк, так и проекты на его основе. В этот период над рубистами стали откровенно стебаться. Например: «Ребята, у меня такой странный баг с кешем — каждый раз, когда захожу на Hacker News, вижу новости о критических уязвимостях в руби». Другой шутник зарегистрировал домен www.didrailshaveamajorsecurityflawtoday.com. В какой-то момент злорадства стало даже слишком много. Информационная война как она есть: пхпшники (не сумевшие изучить Rails) против их более успешных (и я не только про зарплату) коллег-рубистов.

Многие, видя в заголовках обновлений SQL injection или XSS, начинали кричать на каждом углу, что рельсы — решето, а мы все — хипстеры несчастные. По факту (и я не хочу перечислять) большинство таких обновлений закрывают минорные дырки, которые можно было бы эксплуатировать в менее чем 0,01% приложений. Но были и действительно серьезные вещи.

Отправной точкой, по моему скромному мнению, стал мой взлом GitHub в марте. Я достаточно долго занимался агитацией в сообществе защиты от атак с использованием уязвимостей атак mass assignment, но безуспешно. В итоге решил продемонстрировать это на примере GitHub — разработчики GH так и не удосужились провести полный аудит, закрывая лишь отдельные дыры. Ну а остальное ты уже знаешь. После этого началась работа сообщества в области CSRF/XSS/SQLi-защиты, а кульминацией стала комбинация обнаруженных векторов атак, позволившая найти несколько Remote code execution.

Если ты ни разу не сталкивался с Ruby on Rails, то передовая веб-разработка явно не твой конек. Да, мы, рубисты, любим кидать понты. Сложно сказать, смог бы Ruby стать таким популярным без фреймворка Rails, но очевидно — своим успехом Rails полностью обязан гибкости и красоте языка Ruby. Поэтому, когда рубисты обсуждают Rails, они говорят о «тандеме» Ruby & Rails.

Слоган рельс — «Web development that doesn’t hurt», что условно можно перевести как «Веб-разработка, которая не парит». И правда, этот фреймворк прежде всего удобен для программиста. Простота, эффективность и скорость разработки в Ruby on Rails сделала его любимой платформой для разработки как в стартапах, так и в крупных компаниях. RoR начал быстро набирать популярность c момента своего появления, что связано с лаконичностью и «синтаксическим сахаром» Ruby. Разработка прототипа при должной сноровке занимает считаные дни, и переписывать заново его уже не придется. Это позволяет оперативно представить результат инвестору, запустить проект, а потом, при необходимости, легко найти новых разработчиков (разбираться в чужом, но правильно написанном Rails Way коде очень легко).

Rails определенно не подходит для создания очередного SEO-решения (сателлита, дорвея, сплога), как и для создания форума, личной странички (хотя технически такая возможность, конечно, присутствует). Зато идеально подходит для создания серьезных бизнес-проектов различного масштаба и направленности, реализующих новые идеи и решения. Конечно, такие проекты не могут не заинтересовать злоумышленников, что, в свою очередь, и объясняет рост числа атак на RoR-приложения в последнее время.

Какие проекты сделаны на рельсах? GitHub и GitLab — хранение кода, Stripe.com и recurly.com — платежные системы, Diaspora, Look At Me, Groupon, Basecamp, Hulu, Scribd, Shopify, Yellowpages.com, Danbooru и сотни других социальных стартапов, очень популярный проект-трекер Redmine и другие. Также на Ruby написан и сам rubygems.org, главный репозиторий джемов (так называются пакеты/библиотеки в мире руби).

Для начала вводный курс в идеологию фреймворка: Convention over configuration, или все нужно делать по дзену the Ruby/Rails Way. Это звучит очень круто, ведь когда новая команда разработчиков берется за доделку существующего Rails-проекта, то число WTF в секунду ниже, чем у их коллег, использующих PHP. Есть четкий подход к архитектуре приложения — использование MVC (model — view — controller) и то же самое в подходе к безопасности. Есть политика партии, тьфу, 37signals (контора — создатель фреймворка и главный евангелист), и ей нужно следовать. Бытует шутка-цитата из уст создателя Ruby On Rails, (DHH — Дэвид Хейнемейер Хэнссон), что Rails is omakase. Попросту говоря — что вам приготовили, то и ешьте.

Вернемся от философии к безопасности. Откровенно говоря, рельсы хорошо балансируют на грани между «удобно» и «безопасно» — не стесняя действия разработчика, они предоставляют защиту от основных уязвимостей из коробки. XSS, CSRF, SQL inject — рубисту просто не нужно знать значения этих слов, ведь конвенция разработки грамотно решает эти проблемы на корню.

Наконец, сердце RoR — система модулей, gems. Каждый gem хранит внутри себя код и метафайл в формате YAML. Как можно догадаться, если в этот метафайл положить уже известный RCE-exploit для YAML и загрузить такой gem на сервер Rubygems, то можно выполнять любой код в контексте главного репозитория кода руби, скомпрометировав тем самым всю экосистему. Именно это и произошло. Говорят, что админы rubygems были предупреждены за 10 дней, но никаких действий не предприняли. Чтобы продемонстрировать серьезность угрозы, 30 января был анонимно залит gem с говорящим названием «exploit». Очевидно, это была шутка некоего whitehat’а, но ради галочки людям пришлось всю неделю сверять checksum’ы джемов из бэкапов и текущих для выявления скомпрометированных библиотек. Очередное доказательство, что уязвимости надо исправлять быстро, а серьезные уязвимости — мгновенно.

Эта YAML-RCE была и остается самой серьезной уязвимостью в рельсах, затрагивающей огромное число инсталляций Redmine, GitLab и прочих редко обновляемых приложений. Определенно, она была эксплуатирована множество раз на реальных проектах как автоматическими сканерами, так и хакерами, например, были украдены биткоины у биржи Vircurex.

Тем, кто хочет познакомиться с руби поближе, я настоятельно рекомендую изучить синтаксис языка и попробовать его в повседневных задачах. Более того, популярный Metasploit Framework написан на руби и для быстрого «прототипирования» атак нет ничего лучше лаконичного руби. Начать исследования стоит с аудита кода популярных джемов типа Rails, Sinatra, Rack, ибо средний рельс-проект использует сотню-другую сторонних джемов, и в каждом из них может прятаться уязвимость, о которой никто пока не знает. Архитектура «подписывания» и sandbox’инга джемов находится только в самом зачатии, поэтому я уверен, что лично ты можешь найти множество интересных вещей в экосистеме. Удачи!

 

Фреймворк Ruby on Rails и его безопасность

Проведение большинства классических атак (таких как SQL injection, File inclusion, XSS, CSRF) просто невозможно в RoR, или же защита от таких уязвимостей уже включена в фреймворк по умолчанию. Поэтому для того, чтобы провести атаку на RoR-проекты, необходимо эксплуатировать специфические для RoR или самого языка Ruby уязвимости. О них и поговорим.

 

Особенность Ruby Regexp

Рассматривать потенциальные уязвимости начнем с анализа специфики работы Ruby с регулярными выражениями.

Поддержка регулярных выражений в Ruby реализована при помощи стандартного класса Regexp. Сами регулярные выражения являются Perl-совместимыми (PCRE). При этом у них есть одна особенность, о которой практически нигде не упоминается, — многострочный режим обработки регулярных выражений (multiline mode) включен по умолчанию и не может быть выключен с использованием каких-либо модификаторов (интересно, что при этом в Ruby также существует специальный модификатор M, активирующий этот многострочный режим обработки).

Таким образом, по умолчанию регулярное выражение /^\d\d$/ сработает не только для “42”, но и для “ANYTHING\n42\nANYTHING”. Такая ситуация возникает при любом способе создания регулярного выражения в Ruby — будь то конструктор Regexp::new или литерал %r{}.

Практика использования метасимволов ^ и $ широко распространена в других языках программирования (например, PHP, Python, Perl), рекомендации использовать именно их для работы с PCRE-совместимыми регулярными выражениями присутствуют во многих книгах и самоучителях по Ruby. Поэтому весьма велика вероятность того, что Ruby-программист использует именно эти символы вместо корректных \A и \z (или \Z), являющихся «настоящими» указателями начала и конца строки.

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

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

javascript:exploitCode();/*
http://anyproperurl.com
*/

Данный код успешно пройдет проверку регулярным выражением с использованием метасимволов ^ и $ (например, /^https?:\/\/$/), и после щелчка по созданной ссылке выполнится функция exploitCode (при этом само значение URL попало в комментарий). Эта уязвимость может эксплуатироваться как непосредственно, так и, например, путем проведения атаки сlickjacking с попаданием клика пользователя на созданный javascript: URL.

Обработка регулярных выражений в Ruby
Обработка регулярных выражений в Ruby

В своем исследовании я установил, что данной уязвимости подвержены, например, такие крупные проекты, как tumblr.com, scribd.com, github.com, soundcloud.com, а также многие другие.

Рекомендация: используй \A\z вместо популярных, но уязвимых ^$.

 

CSRF

Атака CSRF — одна из любимых тем моих исследований. Я неоднократно доказывал, что CSRF — это уязвимость в протоколе HTTP и его реализации в браузерах, а не в веб-приложениях. Уже который год публикуется информация о десятках данных уязвимостей в популярных сайтах (например, YouTube, Facebook), но консорциум только отмахивается от проблемы. Но сейчас я бы хотел сказать не об этом, а о том, как обстоят дела с этой атакой и сопутствующими уязвимостями в RoR.

В рельсы встроен элегантный механизм, который позволяет разработчикам просто забыть о CSRF и наслаждаться разработкой: в пользовательской сессии хранится созданный приложением Ruby токен с именем authenticity_token. При каждом запросе пользователя хелперы для тега

автоматически вставляют скрытое поле (тег с пометкой hidden) с токеном, а также автоматически подключают jquery_ujs (специальная библиотека, предназначенная для того, чтобы «подружить» jQuery и Rails), добавляющую CSRF-токен во все AJAX-запросы. На стороне сервера для каждого запроса с использованием метода, отличного от GET, проверяется соответствие токена из сессии представленному значению токена из запроса пользователя.Но не все так радужно, как представляется на первый взгляд: существует как минимум две распространенных ситуации, в которых наличие данной защиты становится бесполезным.О первой говорить даже стыдно: многие просто выключают ее. Так, например, рекомендуют многие в своих ответах на Stack Overflow. Это связано с тем, что большинство веб-мастеров вообще не знают, что представляет собой CSRF и зачем от этого нужно защищаться. В результате, когда отдельные разработчики начинают жаловаться на ответы сервера Forbidden, они получают соответствующие советы от таких же «специалистов»: использовать “skip_before_filter :verify_authenticity_token”. Эта конструкция говорит о том, что проверку токена csrf_token необходимо отключить.

Вторая ситуация интересна тем, что она актуальна и для других платформ. Я называю эту проблему «GET Accessible Actions» — это такая ситуация, в которой по задумке разработчика запрос должен осуществляться с использованием метода POST и с токеном, но на деле фреймворк спокойно принимает метод GET и пропускает проверку токена. В случае RoR проблема заключается в использовании метода match в файле routes.rb, описывающем систему обработки путей на сайте. Данный метод предназначен для маппинга определенного действия сразу на все доступные методы HTTP: GET, POST, PATCH, DELETE и так далее. Метод match используется повсеместно, поэтому при анализе защищенности приложения RoR всегда пробуй передавать параметры через альтернативные HTTP-методы (в самом простом случае — GET) и следи за реакцией сервера. Следующее выражение является классической иллюстрацией описываемого случая:

match “/follow”, to: “followings#create” 

Именно благодаря наличию такого выражения и использованию обычного тега

<img src=site/follow?user_id=myid>

я получил сотни фолловеров на сайтах formspring.me, slideshare.net, bitbucket.org и других.

Хотел бы отметить, что в четвертой версии Rails было запрещено использование метода match без параметра «:via». Теперь, если ты хочешь, как и раньше, не ограничивать перечень используемых HTTP-методов, тебе нужно передать аргумент «via: :all».

Рекомендация: независимо от платформы твоего сайта всегда четко разграничивай все действия на POST, как изменяющий информацию запрос (с проверкой токена), и GET, как запрос на получение информации (без токена).

 

XSS

Очень полезна реализованная в RoR защита от XSS при помощи экранирования потенциально опасных символов, включенная по умолчанию. Каждая строка (класс String) помечается специальным флагом html_safe. При этом если данный флаг отсутствует, то перед выводом переменной Rails осуществит ее фильтрацию.

Для вывода безопасных данных принято использовать конструкцию

<%=raw data%>

а для всех остальных (например, значений, которые могут быть модифицированы пользователем):

<%= data %>

Метод raw помечает строку флагом html_safe:

def raw(stringish)
  stringish.to_s.html_safe
end

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

Проблема возникает тогда, когда разработчикам необходимо вставить данные в формате JSON в возвращаемую пользователю страницу. Обычно для этого используют выражение:

<%=data.to_json%>

или для варианта с языком разметки haml:

:javascript
  var data = #{data.to_json}

В первом случае используется конструкция <% — то есть стандартная фильтрация будет применена. Во втором случае JSON, который может содержать HTML-код, не будет очищен. Уязвимость исправлена в четвертой версии Rails, в ней символы <>& заменяются на их Unicode-аналоги.

Рекомендация: не вставлять в inline JavaScript небезопасные данные и вообще не использовать inline javascript / CSS. Альтернативой может быть такой метатег: .

Это может выглядеть неэффективно, зато семантично и безопасно с точки зрения взаимодействия данные — код, обрабатывающий данные.

 

Mass Assignment

Согласно конвенции RoR, параметры передаются в виде хеша: user[username], user[secondname], и уже в контроллере этот хеш переходит в модель — user.update_attributes params[:user]. При этом, если подкидывать в хеш значения других полей таблицы, которые изначально нам не разрешено менять, становится возможным обновить и их вместе с остальными. Например, изменить foreign keys и назначить сущности другого владельца (user_id).

Известная защита от такого поведения RoR — использовать attr_accessible: при создании модели разработчик обязан описать, что именно можно обновлять посредством mass assignment, а что — нельзя. Фактически же такими методами пользуются только настоящие джедаи, то есть те разработчики, которые не только помнят об этой защите, но и не ленятся описывать вручную соответствующие параметры. Основным препятствием к безопасной разработке с использованием данных методов оказывается то, что никто и ничто (даже генераторы моделей) не напоминает разработчику о необходимости их применять.

Особенно пагубно mass assignment влияет на foreign keys, в ситуации, когда один объект можно переназначить другому. Чтобы защиту включили по умолчанию, я проводил активно агитировал разработчиков в тикете #5228 на основной странице Rails (bit.ly/ydMRCB), однако моей идеей мало кто вдохновился.

Параллельно с агитацией я занимался тестированием самого гитхаба, и это принесло свои плоды, так как защита от mass assignment в проекте отсутствовала. Первый пример (его можно применить для множества других сайтов) — обновление дефолтных полей updated_at/created_at. Тикет из 3012 года до сих пор стоит первым в выдаче при сортировке по полю Submitted (рис. 3).

Тикет из будущего на GitHub
Тикет из будущего на GitHub

Вторым примером стала смена значения public_key[user_id] моего ключа на ID пользователя Rails и последующий коммит в rails/rails — репозиторий Rails, хранящийся на GitHub, написанном на Rails (рис. 4).

Последствия коммита в репозиторий rails/rails
Последствия коммита в репозиторий rails/rails

Нельзя назвать мой наглый поступок ответственным, хоть я и уведомил администрацию о похожих уязвимостях еще за три дня до этого. Вместо полного аудита кода на наличие mass assignment они запатчили лишь частные случаи, поэтому я был вынужден поступить не по whitehat’ски. Это принесло свои плоды — спустя пять часов после коммита Rails Core Team сделала whitelist_attributes обязательным по умолчанию (заставляет прописывать attr_accessible в моделях), а также добавила атрибут attr_accessible в генераторы. Вероятно, это было сделано под воздействием общественного мнения — о том коммите написали многие сайты.

В Rails 4 вместо старой защиты в модели будет использоваться джем strong_parameters для фильтрации ключей тем же способом, но в контроллере. Этот способ выглядит более логичным, так как контроллер является первым рубежом обороны от ошибок, связанных с некорректной обработкой данных, поступающих от пользователя.

Рекомендация: всегда использовать whitelist и делать защиту включенной по умолчанию, не надеясь на самих пользователей.

 

SQL injection

Хотя ORM-рельс в большинстве случаев экранирует входные параметры, есть такие служебные методы, которые подразумевают передачу только безопасных параметров. Например, Order.where(:user_id => 1).joins(params[:table]) — параметр table никак не будет очищен, да и джойнить произвольную таблицу — изначально плохая идея.

Рекомендация: Для полного списка таких опасных методов советую посмотреть сайт rails-sqli.org и убедиться, что для создания SQLi в рельс-приложении надо иметь руки немного не из того места.

 

Сессии

В RoR сессии хранятся по умолчанию в signed cookie, представляющей собой обычную строку, подписанную секретным ключом HMAC. Многие разработчик полагают, что пользовательская сессия — это что-то по умолчанию безопасное и недосягаемое для пользователя. Да, пользователь не может модифицировать значения параметров сессии, так как она подписана сессионным ключом приложения — session_secret, зато он может прочитать все, что записано в сессии (например, значения user_id, access_token или path_to_secret_file). Вот так, например, выглядит _gh_sess cookie на github.com:

BAh7DDoQX2Nzc ... AGOgpAdXNlZHsA—
d12b0f42ed9881fbv55cc9559d50adwf5f5638d2

Данное значение состоит из двух частей: первая часть значения представляет собой строку, закодированную по алгоритму Base64, вторая часть — ее MD5-подпись. Попробуем декодировать первую часть строки при помощи функций atob(decodeURIComponent()) и получим следующее значение:

"{:_csrf_token"19yv3VZY8veGCQXyS3dl47XGB9r4rzWVUNZqUFqSmWNI=:session_id"%76f701b09a1b5a1831a51a309ff8f79d: userieª:contextI"/:EF:fingerprint"%5ffecf01f27d79b4ff0dbeaa39568eb7:return_toI"(https://github.com/settings/profile; TI"
flash; FIC:'ActionController::Flash::FlashHash{:
@used{"

Собственно говоря, ничего, кроме раскрытия данных, этот баг не несет. В Rails 4 для хранения сессий уже используется encrypted session storage, что существенно ограничивает возможность получения полезных данных из сессии, так как она хранится в зашифрованном виде.

Рекомендация: лучше не хранить ничего на стороне клиента, а в качестве session ID использовать неугадываемую строку, соответствующую строчке в базе данных, для этого есть джем activerecord-session_store.

 

to_sym

Symbol — это особый тип данных в Ruby, являющийся, по сути, константой, при этом сами символы никогда не удаляются сборщиком мусора. Поэтому, если приложение создает символы на основании контролируемых пользователем данных и при этом указать длинные последовательности случайных букв/цифр, возможен отказ в обслуживании. Основной задачей в этом случае становится поиск места, в котором пользовательский ввод приводится к типу symbol.

Дефолтная структура свежесозданного проекта
Дефолтная структура свежесозданного проекта

Хотя со временем код рельс «очистили» от символизации, однако до сих пор некоторые разработчики злоупотребляют этим в своих приложениях и контроллерах. Очень часто встречается, например: I18n.locales.include?(params[:locale].to_sym) — разработчик только что привел параметр locale к символу (а он может быть очень длинным), забив тем самым память.

pic dlinn

Я, например, находил возможность DoS в Rack (единый интерфейс для большинства веб-фреймворков на Ruby), который приводил к символу часть заголовка Authorization (:basic, :digest, :blahblahverylong):

def parts
  @parts ||= @env[authorization_key].split(' ', 2)
end
@scheme ||= parts.first.downcase.to_sym

Рекомендация: не приводить к символам пользовательский контент.

 

Remote code execution

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

Исторически сложилось так, что рельсы обрабатывали параметры, представленные в различных форматах: urlencoded (обычные формы), JSON и даже XML. Кроме того, XML мог содержать внутри себя ноду, представленную в формате YAML, например:

<exploit type=”yaml”>---</exploit>

Кроме того, YAML мог инстанцировать (по сути, вызывать Object.new) любые классы в атакуемой системе, а потом назначать свойства через метод [] (доступ к элементу массива).

В конце концов исследователи нашли такие классы в системе, которые приводили к выполнению кода в результате обработки поступающих от пользователя произвольных данных. На момент публикации информации об этой уязвимости ей были подвержены все сайты на RoR (необходимо отметить, что в четвертой версии Rails отключена обработка XML-параметров по умолчанию). Рабочий эксплойт для данной уязвимости выглядит следующим образом:

    --- !ruby/hash:ActionController::Routing:: /
     RouteSet::NamedRouteCollection
    ? #{encoded_payload}
    : !ruby/struct
      defaults:
    :action: create
    :controller: foos
      required_parts: []
      requirements:
    :action: create
    :controller: foos
      segment_keys:
    - :format

Дальше — больше, и по похожей схеме. Оказалось, что JSON.parse вызывает внутри себя метод JSON.load, а JSON.load поддерживает инстанцирование “json_creatable?” классов. В рельсах было достаточно таких “json_creatable?” классов, чтобы довести это до удаленного выполнения произвольного кода. Хоть в паблике я эксплойта до сих пор не видел, Бен Мерфи (Ben Murphy), нашедший этот баг, гарантировал мне, что у него есть рабочий RCE.

Рекомендация: не использовать YAML и JSON.load для парсинга пользовательского инпута.

 

Гибкость Rails API

В четвертую версию Rails был внесен ряд приятных изменений, связанных с безопасностью. Например, в ответ сервера по умолчанию добавлен HTTP-заголовок «X-Frame-Options: SAMEORIGIN» для предотвращения clickjacking-атаки.

Тем не менее есть в философии Rails одна деталь, от которой нельзя так быстро избавиться, — гибкость. Rails — это такой швейцарский ножик, и, к сожалению, многие разработчики не до конца понимают, как все работает изнутри и какие «секреты» хранит этот фреймворк. Приведу пару примеров, как гибкость может пагубно влиять на безопасность.

Допустим, есть метод redirect_to, который может принимать либо строчку, либо замыкание, либо символ :back, либо объект ORM, либо хеш с опциями. Выражение redirect_to params[:to] подразумевает, что пользователь будет перенаправлен на путь из параметра “to”. Стоп, а что, если мы подкинем вместо обычной строки хеш «?to[status]=200&to[protocol]=javascript:alert(0)//», что эквивалентно redirect_to status: 200, protocol: ‘javascript:alert(0)//’. В результате ответ сервера будет:

<html>
<body>You are being 
<a  href="javascript:alert(0)//HOST/">redirected</a>
</body>
</html>

настойчиво предлагающий пользователю нажать на XSS-ссылку.

Все рельс-сайты принимают в теле запроса JSON, и это значит, что вместо любой строчки ты можешь послать любую структуру хешей и массивов. Очередной пример — при создании записи с помощью Post.create(params[:post]) можно положить в “post” несколько сотен/тысяч объектов класса Post, попросту говоря — спамить. При этом вместо ожидаемого {“post”:{“title”:”Title 1”}} придет {“post”:[{“title”:”Title 1”},{“title”:”Title 2”},{“title”:”Title 3”}…]}.

Аналогичная ситуация и с email-рассылками! Попробуй послать в теле запроса email[]=vasya@gmail.com&email[]=lena@gmail.com&email[]=sasha@gray.com&.., и ты заставишь сервер делать рассылку своего письма по всем этим адресам. Как видишь, гибкость сильно увеличивает поверхность атаки, а у Rails очень гибкий API.

Рекомендация: использовать .to_s/.to_i (приводить к строчкам/числам) там, где Rails API может повести себя непредсказуемо.

 

Nils, integers и brute force

Первым багом, связанным с типами параметров, был nil. Дело в том, что Rack парсит параметры таким образом, что ?var дает params[:var]==nil, а значит, ?var[] дает массив [nil]. При этом многие разработчики часто проверяют наличие токена при восстановлении пароля следующим образом:

if params[:token]
 User.find_by_token params[:token]
end

Если передать ?token[] в адресной строке, то if params[:token] пройдет проверку, а ORM вернет первую же запись с пользователем, у которого поле token не задано (пустое). Такая ошибка была найдена мною в системе электронной коммерции Spree. Используя ссылку вида http://example.com/api?api_key[], можно было делать API-запросы от лица суперадмина, так как по умолчанию api_key получался пустой.

Спустя несколько недель после обнаружения описанной проблемы исследователи обратили внимание на то, как MySQL осуществляет сравнение строк с числами. В частности, выражение “random_token” = 0 вернет логическое значение true, так как будет осуществлено приведение типа строки к нулю. При этом возникает вопрос — как можно передать в приложение значение нуль? Ответ прост — используй JSON (например, объект {“token”:0}), и вот ты уже меняешь кому-то пароль! После обнаружения этой особенности авторы фреймворка отказывались что-либо менять, но после публикации деталей уязвимости и под воздействием общественного мнения разработчики решили исправить данное поведение приведя типы полей к тому, что от них ожидается в схеме базы, — строки к строкам, числа к числам.

Рекомендация: можно использовать баг в стиле brute-force — вместо ?token=123 отсылай POST body с содержанием token[]=1&token[]=2…, что позволит тебе за раз проверять более 10 тысяч вариантов.

 

WWW

  • Описание формата Haml: haml.info
  • Описание формата YAML: yaml.info

 

Заключение

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

В блогосфере четко прослеживается усилившийся интерес к безопасности. Многие начали писать книги с названиями типа Ruby Security, некоторые создают онлайн-сканеры, остальные работают над brakeman (статический анализатор кода для Rails). Также есть Security Monitor от создателя Code Climate, который делает похожую работу, но «в облаке» и, разумеется, платный — 74 доллара в месяц (поэтому в годовой перспективе лучше нанять, например, меня :)). Прогресс определенно есть, и многие шутят, что если раньше рубисты были «одержимы» тестированием, то сейчас это место заняла безопасность.

Результат работы сканера Brakeman
Результат работы сканера Brakeman

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

 

Оставить мнение

Check Also

Найден способ подменить относительный идентификатор RID и повысить привилегии в Windows

Специалист компании CSL нашел способ подменять RID в Windows, что позволяет получить права…