Mass Assignment в RoR.

Февраль 4, 2010


Mass Assignment (массовое назначение) является причиной уязвимостей сайтов на rails с момента появления фреймворка на свет. О�?ибка программиста, как зачастую это бывает, сводится к отсутствию проверки входных параметров.
Для примера создадим простенькое приложение

$ rails massVul
$ cd massVul/
$ script/generate scaffold user name:string admin:boolean

Таким образом мы создадим основу для приложения с пользователями, в которой можно указать имя в поле name, а также есть поле admin, которое легко использовать при разграничении прав пользователей. К примеру запросом, является ли этот пользователь администратором, и если да, то позволяются ему определенные действия. Конечно, мы не настолько глупы чтобы позволять обычным пользователям ставить галочку, поэтому мы правим на�? вид и удаляем все что связано с галочкой admin.

<!-- app/views/users/new.html.erb -->
<h1>New user</h1>
<% form_for(@user) do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.label :admin %><br />  <!-- то есть вот -->
    <%= f.check_box :admin %>  <!-- эти строчки -->
  </p>
  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>
<%= link_to 'Back', users_path %>

Ту же операцию необходимо провести с видом app/views/users/update.html.erb. �? новичок девелопер начинает думать, что теперь нет никакой возможности поставить галочку(1ку, true) в таблицу, в чем и о�?ибается. Давайте теперь посмотрим на контроллер users_controller.rb и найдем следующую строчку.

# app/controllers/users_controller.rb
    @user = User.new(params[:user])

Вот здесь и происходит массовое присвоение, ведь все что передается в параметрах params напрямую передается в модель юзеров. Злоумы�?ленник же может сделать страничку, ну или просто послать пост запрос, в котором передаст похожие данные:

:user => { :name => hacker, :admin => 1}

и обретет администраторские права.
Логичным выводом из вы�?еописанной проблемы будет не забывать проверять входные данные и сохранять только те, что позволены к сохранению программистом. Следует заметить что по умолчанию к mass assign’у допускаются абсолютно все параметры.

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

# app/models/user.rb
class User < ActiveRecord::Base
  attr_protected :admin
end

Таким образом злоумы�?ленник не сможет изменить параметр admin. Но следует учесть, что с на�?ей моделью пользователя зачастую связаны и другие модели, например создание списка задач или создание статей в случае с блогом. Таким образом злоумы�?ленник может создать специальный запрос и к на�?ему пользователю добавить или удалить задачу, удалить статью и так далее.

Ре�?ением данной проблемы будет являться использование attr_accessible в модели. После появления в модели attr_accessible к массовому присвоению становятся доступны только те параметры, что указаны в качестве аргументов к attr_accessible, а все остальные запрещены.

# app/models/user.rb
class User < ActiveRecord::Base
  attr_accessible :name
end

К слову, nifty-generators по умолчанию генерируют модель и автоматически дописывает строку attr_accesible со всем списком параметров, переданных при создании скаффолда. Так что, чтобы не допустить возможность о�?ибки из-за массового присвоения, необходимо после создания скаффолда из модели удалить те параметры, что запрещены к изменению через массовое присвоение.

Подводя итог, скажем, что использование attr_protected и attr_accessor противоположны по значению. attr_protected закрывает возможность изменения параметров через mass assignment в тот момент когда все другие параметры открыты, attr_accessible открывает возможность изменения параметров через mass assignment, когда все другие закрыты.

�?спользование attr_protected и attr_accessible – не единственный способ избежания данной уязвимости, но самый простой. Ко всему прочему существуют плагины для обнаружения уязвимости, ведь зачастую очень легко забыть дописать строчку или же бывает необходимость проверить какой-либо плагин, используемый в приложении, не приведет ли он к уязвимости. Вот один из них: установка и проверка приложения всего за 2 действия.

$ script/plugin install git://github.com/mhartl/find_mass_assignment.git
$ rake find_mass_assignment

6 Комментари(я/ев) to “Mass Assignment в RoR.”

  1. Gemko Says:

    Статья полезная, хотя настолько ленивые фреймворки помойму,-зло =)

  2. sadreamer Says:

    Willson, просвети незнающего, а как rails поддерживает авторизацию юзера? Cookie, сессии, http или какой-то другой механизм? Можно ли было вообще обойтись без свойства admin, сохранив флаг админа, например, внутри сессии?
    P.S. С автоприсвоением свойствам класса значений, при�?ед�?их извне, rails жгет, лично я ничего подобного не видел рань�?е. Но согласен с предыдущим автором, что сли�?ком ленивые инструменты – зло, и часто причина уязвимостей.

  3. willson Says:

    @sadreamer, авторизация будет такая, какую сделае�?ь, легче всего организовать естественно на сессиях и боль�?инство плагинов так и работают, но и куки и http использовать не проблема. �? да, можно вообще обойтись без табличного свойства админ.
    P.S. Как это не сталкивался, а ты вот представь, что ты принимае�?ь все что в $_GET[] и скажем у тебя включен register_globals?

  4. sadreamer Says:

    > $_GET[] и скажем у тебя включен register_globals

    Ну одно дело когда на уровне языка такое присваивание происходит (кстати, от register_globals боль�?е проблем чем пользы, он нынче deprecated), другое – когда на уровне инструмента. Может из этого и можно извлекать какую-то выгоду (быстроту разработки например), но только очень аккуратно.

  5. willson Says:

    Конечно, так удобнее, ведь в немногих моделях у тебя есть параметры которые ты определяе�?ь как private или protected. А когда все public, то и заботиться не нужно (кстати валидация данных в рельсах – это просто конфетка)

  6. sadreamer Says:

    > в немногих моделях у тебя есть параметры которые ты определяе�?ь как private или protected

    Private и protected свойств как раз боль�?е, редко встрети�?ь модель, в которой какие-то свойства доступны для прямого редактирования извне. Если редактирование и происходит, то как правило используются сеттеры, магические методы и т.п. Напрямую присваивать значения свойствам некорретко как с точки зрения безопасности, так и с точки зрения ООП (если только действительно свойство имеет право быть public, т.е. нас мало заботит его содержимое, хотя я лично в своей практике не помню, чтобы при�?лось делать какое-то свойство с публичной видимостью)

Leave a Reply

Нам помогают
Дружественные сайты: