Rails всегда предлагает новые и креативные новые функции, и Rails 4 не является исключением. Одна из новых функций в Rails 4 — Сильные Параметры .
Основная идея, лежащая в основе Strong Parameters, состоит в том, чтобы переместить защиту от массового присвоения из модели в контроллер, которому она принадлежит.
Просто чтобы мы все были на одной странице, давайте поговорим о массовом назначении, прежде чем сосредоточимся на сильных параметрах.
Mass-Assignment: присвоение атрибутов модели в хеше
Давайте возьмем простой пример.
Предположим, у нас есть модель пользователя с именем, адресом электронной почты и администратором. Admin — это логический атрибут, используемый для указания, имеет ли пользователь права администратора.
Rails способ создания пользователя выглядит так:
params[:user] = {:name => ‘Foo’,:email => ‘[email protected]’} | |
@user = User.new(params[:user]) |
и обновление:
@user = User.update_attributes(params[:user]) |
Это часто делается путем отправки параметров через форму и создания / обновления объекта в контроллере. Таким образом, нам не нужно устанавливать значение каждого атрибута.
Проблема с Mass-Assignment: уязвимость безопасности
Массовое назначение избавляет нас от необходимости присваивать значения каждому атрибуту модели, но может создавать проблемы. Поскольку мы не ограничиваем какие атрибуты можно установить и не проверяем их значения, злоумышленник может присвоить любое значение любому атрибуту. В нашем примере он мог установить значение admin true, сделав себя суперпользователем.
Вот как может выглядеть URL
http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1
или через форму с помощью консоли браузера
После нажатия на кнопку вы увидите
Таким образом, пользователь может использовать уязвимость безопасности.
Как вы можете догадаться, это плохо, и это становится хуже. Это не ограничивается только одной моделью, если у нас есть модельные отношения, такие как has_many, has_one или has_many: through
class Account < ActiveRecord::Base | |
has_many :rooms | |
accepts_nested_attributes_for :rooms | |
end | |
class Room < ActiveRecord::Base | |
belongs_to :account | |
end |
Когда создается учетная запись, комнаты также можно создавать с помощью массового назначения (params [: account]). Другими словами, ссылочные таблицы также могут стать целью злоумышленников
Есть живой пример такого рода уязвимости безопасности, которая случилась на Github. Из-за массового назначения пользователь передал свой ssh-ключ через форму обновления открытого ключа, чтобы добавить себя в репозиторий Rails и создал коммит.
Вы можете прочитать больше об этой уязвимости здесь .
Как Избежать Атаки Массового Назначения
Теперь, когда мы знаем, что такое массовое назначение, мы можем решить эту проблему.
Прежде всего, не паникуйте, у Rails есть решения для этого.
Есть два способа:
1. В Rails есть метод класса attr_protected, который используется для указания атрибутов, которые не могут быть частью массового присвоения.
class User < ActiveRecord::Base | |
attr_protected :admin | |
end |
Теперь значение admin недоступно для массового назначения. Злоумышленники не могут обновить это значение в URL или через форму.
2. Другой способ защитить все модели в вашем приложении от массового назначения — установить для config.active_record.whitelist_attributes
config.active_record.whitelist_attributes = true |
Теперь все атрибуты модели недоступны для массового назначения. Но если мы хотим, чтобы некоторые атрибуты были доступны для массового назначения, мы можем использовать метод attr_accessible
class User < ActiveRecord::Base | |
attr_accessible :name | |
end |
attr_accessible прямо противоположен attr_protected. Когда атрибут передается методу attr_accessible, он становится доступным для массового назначения
В Rails 3.2.3 config.active_record.whitelist_attributes имеет значение true по умолчанию, и во всех моделях метод attr_accessible используется для внесения в белый список атрибутов.
Rails включил эту функцию сразу после того, как хакеры нарушили безопасность Github, как я упоминал ранее.
Сильные параметры: новый способ защиты от массовых назначений
Защита массовых назначений будет сделана по-новому в Rails 4. Как упоминалось ранее, защита массовых назначений перемещается в контроллер, которому она принадлежит.
Сегодня, имея драгоценный камень Strong Parameters от DHH , вы можете просто позвонить «РАЗРЕШЕНИЕ».
Чтобы изучить его подробнее, давайте напишем некоторый код.
Скажем, у нас есть приложение book_store с моделью под названием Book. Модель Book имеет атрибуты name, author и public (boolean). У нас есть аутентификация пользователя на основе роли (администратор, пользователь).
Массовая защита заданий на уровне модели
В книжной модели:
class Book < ActiveRecord::Base | |
attr_accessible :name, :public, :author | |
end |
Каждый пользователь может создавать и обновлять книги и делать их общедоступными из пользовательского интерфейса.
Если мы хотим ограничить пользователей, которые не являются администраторами, обновлением атрибута public, нам нужно сделать что-то вроде:
class Book < ActiveRecord::Base | |
attr_accessible :name, :author, :public as : :admin | |
attr_accessible :name, :author, as : :user | |
end |
В BooksController нам нужно сделать так:
class BooksController < ApplicationController | |
def create | |
@book = Book.new(params[:book], as : current_user.try(:admin) ? :admin : :user) | |
respond_to do |format| | |
if @book.save | |
format.html { redirect_to @book notice ‘Book was successfully created.’ } | |
else | |
format.html { render action : «new» } | |
end | |
end | |
end | |
def update | |
@book = Book.find(params[:id]) | |
respond_to do |format| | |
if @book.update_attributes(params[:book], as : | |
current_user.try(:admin) ? :admin : :user) | |
format.html { redirect_to @book, notice : ‘Book was successfully updated.’ } | |
else | |
format.html { render action : «edit» } | |
end | |
end | |
end | |
end |
Теперь только администратор может обновлять публичное поле через форму. Теперь мы добавляем новую роль с именем report_user, которая может только обновлять имя.
class Book < ActiveRecord::Base | |
attr_accessible :name, :author, :public as : :admin | |
attr_accessible :name, :author as : :user | |
attr_accessible :name, as : :reporting_user | |
end |
Мы должны добавить еще несколько условий в контроллер, как
class BooksController < ApplicationController | |
def create | |
@book = Book.new(params[:book], as : user_role) | |
respond_to do |format| | |
if @book.save | |
format.html { redirect_to @book notice ‘Book was successfully created.’ } | |
else | |
format.html { render action : «new» } | |
end | |
end | |
end | |
def update | |
@book = Book.find(params[:id]) | |
respond_to do |format| | |
if @book.update_attributes(params[:book], as : | |
user_role) | |
format.html { redirect_to @book, notice : ‘Book was successfully updated.’ } | |
else | |
format.html { render action : «edit» } | |
end | |
end | |
end | |
private | |
def user_role | |
current_user.try(:admin) ? :admin : (current_user.try(:user) ? :user : :reporting_user) | |
end | |
end |
Как вы можете видеть, все мы работаем с контролем доступа пользователей на основе роли пользователя, которая больше связана с контроллером, а не с моделью. Мы знаем, что контроллер управляет потоком между пользователем и приложением, аутентификацией и авторизацией, поэтому защита масс-назначений должна выполняться в контроллере, а не в модели.
Давайте теперь посмотрим на сильные параметры , сначала в Rails 3.
Массовая защита заданий на уровне контроллера: драгоценный камень с сильными параметрами
В Rails 3.2.7 атрибуты включены в белый список по умолчанию, поэтому сначала нам нужно удалить (или установить для него значение «false») следующий код в config / application.rb
config.active_record.whitelist_attributes = true |
Далее добавить добавить драгоценный камень в Gemfile
gem ‘strong_parameters’ |
и запустите bundle, чтобы активировать strong_parameters.
Добавьте следующую строку в модель Book:
class Book < ActiveRecord::Base | |
include ActiveModel::ForbiddenAttributesProtection | |
end |
Это вызовет исключение ActiveModel :: ForbiddenAttributes, потому что оно использует массовое назначение
Теперь в нашем контроллере мы обрабатываем массовое присвоение, вызывая разрешение :
class BooksController < ApplicationController | |
def create | |
@book = Book.new(book_params) | |
respond_to do |format| | |
if @book.save | |
format.html { redirect_to @book, notice : ‘Book was successfully created.’ } | |
else | |
format.html { render action : «new» } | |
end | |
end | |
end | |
def update | |
@book = Book.find(params[:id]) | |
respond_to do |format| | |
if @book.update_attributes(book_params) | |
format.html { redirect_to @book, notice : ‘Book was successfully updated.’ } | |
else | |
format.html { render action : «edit» } | |
end | |
end | |
end | |
private | |
def book_params | |
if current_user && current_user.admin? | |
params[:book].permit(:name, :author, :public) | |
else | |
params[:book].permit(:name, :author) | |
end | |
end | |
end |
Кроме того, вы можете специализировать этот закрытый метод для проверки допустимых атрибутов для каждого пользователя:
params[:book].permit(:name,:author,:public)
Ты можешь сделать :
params.require(:book).permit(:name,:author,:public) |
Если пользователь, отличный от администратора, попытается добавить / обновить значение открытого поля, это не вызовет никакой ошибки, но будет игнорировать это обновление.
Согласно документам, он поддерживает вложенные атрибуты. Например, если в книге много глав, то в контроллере мы можем вызвать allow, например:
params[:book].permit(:name,:author,:chapters_attributes => [:number_of_pages]) |
Сильные параметры будут частью Rails 4.
Если вы создадите пример приложения с Rails 4 и создадите пользователя scaffold с атрибутами name и email, он сгенерирует приватный метод user_params:
def user_params | |
params.require(:user).permit(:name, :email) | |
end |
Существует много дискуссий по этому вопросу. Вы можете проверить коммиты здесь
Заворачивать
Я думаю, что мы почти охватили большинство вещей о массовом назначении и сильных параметрах.
С сильными параметрами:
- Вы можете сохранить код вашей модели в чистоте
- Вы можете обрабатывать авторизацию и доступ к параметрам в контроллере, к которому он принадлежит
Если вы хотите узнать больше о массовых назначениях и параметрах strong_parameters:
- http://blog.mhartl.com/2008/09/21/mass-assignment-in-rails-applications/
- http://guides.rubyonrails.org/security.html
- http://railscasts.com/episodes/371-strong-parameters
- http://weblog.rubyonrails.org/2012/3/21/strong-parameters/
- https://github.com/blog/1068-public-key-security-vulnerability-and-mitigation
И если вам понравилось читать этот пост, вы полюбите Learnable ; место, чтобы узнать новые навыки и приемы у мастеров. Участники получают мгновенный доступ ко всем электронным книгам SitePoint и интерактивным онлайн-курсам, таким как Jump Start Rails .
Комментарии к этой статье закрыты. У вас есть вопрос о Ruby on Rails? Почему бы не спросить об этом на наших форумах ?