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

 

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии