Статьи

Rails 4 Quick Look: сильные параметры


Rails всегда предлагает новые и креативные новые функции, и Rails 4 не является исключением. Одна из новых функций в Rails 4 — Сильные Параметры .
Основная идея, лежащая в основе Strong Parameters, состоит в том, чтобы переместить защиту от массового присвоения из модели в контроллер, которому она принадлежит.

Просто чтобы мы все были на одной странице, давайте поговорим о массовом назначении, прежде чем сосредоточимся на сильных параметрах.

Mass-Assignment: присвоение атрибутов модели в хеше

Давайте возьмем простой пример.

Предположим, у нас есть модель пользователя с именем, адресом электронной почты и администратором. Admin — это логический атрибут, используемый для указания, имеет ли пользователь права администратора.

Rails способ создания пользователя выглядит так:

params[:user] = {:name => ‘Foo’,:email => ‘[email protected]’}
@user = User.new(params[:user])

view raw
SP11
hosted with ❤ by GitHub

и обновление:

@user = User.update_attributes(params[:user])

view raw
gistfile1.rb
hosted with ❤ by GitHub

Это часто делается путем отправки параметров через форму и создания / обновления объекта в контроллере. Таким образом, нам не нужно устанавливать значение каждого атрибута.

Проблема с 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

view raw
gistfile1.rb
hosted with ❤ by GitHub

Когда создается учетная запись, комнаты также можно создавать с помощью массового назначения (params [: account]). Другими словами, ссылочные таблицы также могут стать целью злоумышленников

Есть живой пример такого рода уязвимости безопасности, которая случилась на Github. Из-за массового назначения пользователь передал свой ssh-ключ через форму обновления открытого ключа, чтобы добавить себя в репозиторий Rails и создал коммит.

Вы можете прочитать больше об этой уязвимости здесь .

Как Избежать Атаки Массового Назначения

Теперь, когда мы знаем, что такое массовое назначение, мы можем решить эту проблему.

Прежде всего, не паникуйте, у Rails есть решения для этого.
Есть два способа:

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

class User < ActiveRecord::Base
attr_protected :admin
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Теперь значение admin недоступно для массового назначения. Злоумышленники не могут обновить это значение в URL или через форму.

2. Другой способ защитить все модели в вашем приложении от массового назначения — установить для config.active_record.whitelist_attributes

config.active_record.whitelist_attributes = true

view raw
gistfile1.rb
hosted with ❤ by GitHub

Теперь все атрибуты модели недоступны для массового назначения. Но если мы хотим, чтобы некоторые атрибуты были доступны для массового назначения, мы можем использовать метод attr_accessible

class User < ActiveRecord::Base
attr_accessible :name
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

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

view raw
gistfile1.rb
hosted with ❤ by GitHub

Каждый пользователь может создавать и обновлять книги и делать их общедоступными из пользовательского интерфейса.

Если мы хотим ограничить пользователей, которые не являются администраторами, обновлением атрибута public, нам нужно сделать что-то вроде:

class Book < ActiveRecord::Base
attr_accessible :name, :author, :public as : :admin
attr_accessible :name, :author, as : :user
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

В 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

view raw
gistfile1.rb
hosted with ❤ by GitHub

Теперь только администратор может обновлять публичное поле через форму. Теперь мы добавляем новую роль с именем 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

view raw
gistfile1.rb
hosted with ❤ by GitHub

Мы должны добавить еще несколько условий в контроллер, как

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

view raw
gistfile1.rb
hosted with ❤ by GitHub

Как вы можете видеть, все мы работаем с контролем доступа пользователей на основе роли пользователя, которая больше связана с контроллером, а не с моделью. Мы знаем, что контроллер управляет потоком между пользователем и приложением, аутентификацией и авторизацией, поэтому защита масс-назначений должна выполняться в контроллере, а не в модели.

Давайте теперь посмотрим на сильные параметры , сначала в Rails 3.

Массовая защита заданий на уровне контроллера: драгоценный камень с сильными параметрами

В Rails 3.2.7 атрибуты включены в белый список по умолчанию, поэтому сначала нам нужно удалить (или установить для него значение «false») следующий код в config / application.rb

config.active_record.whitelist_attributes = true

view raw
gistfile1.rb
hosted with ❤ by GitHub

Далее добавить добавить драгоценный камень в Gemfile

gem ‘strong_parameters’

view raw
gistfile1.rb
hosted with ❤ by GitHub

и запустите bundle, чтобы активировать strong_parameters.

Добавьте следующую строку в модель Book:

class Book < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Это вызовет исключение 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

view raw
gistfile1.rb
hosted with ❤ by GitHub

Кроме того, вы можете специализировать этот закрытый метод для проверки допустимых атрибутов для каждого пользователя:
params[:book].permit(:name,:author,:public)

Ты можешь сделать :

params.require(:book).permit(:name,:author,:public)

view raw
gistfile1.rb
hosted with ❤ by GitHub

Если пользователь, отличный от администратора, попытается добавить / обновить значение открытого поля, это не вызовет никакой ошибки, но будет игнорировать это обновление.

Согласно документам, он поддерживает вложенные атрибуты. Например, если в книге много глав, то в контроллере мы можем вызвать allow, например:

params[:book].permit(:name,:author,:chapters_attributes => [:number_of_pages])

view raw
gistfile1.rb
hosted with ❤ by GitHub

Сильные параметры будут частью Rails 4.
Если вы создадите пример приложения с Rails 4 и создадите пользователя scaffold с атрибутами name и email, он сгенерирует приватный метод user_params:

def user_params
params.require(:user).permit(:name, :email)
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Существует много дискуссий по этому вопросу. Вы можете проверить коммиты здесь

Заворачивать

Я думаю, что мы почти охватили большинство вещей о массовом назначении и сильных параметрах.

С сильными параметрами:

  • Вы можете сохранить код вашей модели в чистоте
  • Вы можете обрабатывать авторизацию и доступ к параметрам в контроллере, к которому он принадлежит

Если вы хотите узнать больше о массовых назначениях и параметрах strong_parameters:

И если вам понравилось читать этот пост, вы полюбите Learnable ; место, чтобы узнать новые навыки и приемы у мастеров. Участники получают мгновенный доступ ко всем электронным книгам SitePoint и интерактивным онлайн-курсам, таким как Jump Start Rails .

Комментарии к этой статье закрыты. У вас есть вопрос о Ruby on Rails? Почему бы не спросить об этом на наших форумах ?