ひょんなことから Rails4 をインストールしてしまった俺達は
attr_accessibleやattr_protectedを使わずに
Strong Parameters を使うことになってしまっていた!
ActionController::StrongParameters
rails/strong_parameters
初めての Rails で右も左も分からない状況で
いきなり Strong Parameters と言われてもよくわからないので以下についてまとめます。
- Mass Assignment とは
- Mass Assignment 脆弱性
- Rails4 以前の Mass Assignment 脆弱性対策
- Rails4 の Mass Assignment 脆弱性対策の Strong Parameters について
Mass Assignment とは
Rails ではこんなコードをよく見ると思います。
def create @user = User.new(params[:user]) unless @user.save render 'new' end endUserモデルにnameとemailという属性が設定されていて、
params[:user]に{name: 'willnet', email: 'willnet@example.com'}のような
パラメータが入っていたとき、上記のUser.new(params[:user])で一度にnameとemailが
設定されます。これが mass assignment です。属性が多いときなど大変便利です。
Rails4.0に含まれる strong_parameters について - willnet.in
Mass Assignment 脆弱性
先ほどの例ではnameとemailという属性が設定されていました。
この2つの属性の他に、システム側で自動で割り振られるtokenという属性が存在したとします。
tokenはユーザには変更させたくありません。
さて、 それではUser#nameとUser#emailを変更するための
update アクションを書いてみましょう。
edit の view には name と email を変更するための text_field だけが存在するとします。
def update @user = User.find(params[:id]) unless @user.update_attributes(params[:user]) render 'edit'& end end上記のコードは基本的にはうまく動くはずです。ただしユーザが普通にブラウザを使う限りは。
上記のような方法を使った場合、ユーザに編集させたくないtoken属性が更新されてしまいます。
- chromeのデベロッパーツールなどで
<input type="text" name="user[token]" value="hoge" />などのタグを
form中に生成してsubmitする- curlやtelnetなどで直接user[token]=hogeのようなリクエストを、
通常のリクエストに追加して送信する
これが mass assignment の脆弱性と呼ばれるものです。
Rails4.0に含まれる strong_parameters について - willnet.in
Rails4 以前の Mass Assignment 脆弱性対策
attr_accessibleやattr_protectedが提供されていました。Rails 3.1以上からはattr_accessibleやattr_protectedに role という機能が導入されました。
Rails2系(および3.0)だと後述のroleが設定できないため、
User#nameだけ更新したい場合とUser#nameとUser#email両方を更新させたい場合の
2種類があるケースなど、同じモデルに複数種類の mass assignment 脆弱性対策をかけたくなります。
Rails4.0に含まれる strong_parameters について - willnet.in
role の設定が煩雑になった結果(?)、class User < ActiveRecord::Base attr_accessible :name attr_accessible :name, :email, as: :name_and_email endas オプションで role の名前を指定して、
@user.update_attributes(params[:user], role: 'name_and_email')のように role オプションで適用したいattr_accessible(もしくはattr_protected)を指定します。
role がない場合はデフォルトのもの(上記のケースはattr_accessible :name)が使用されます。
これにより大分きちんと書けるようになったのですが、
多くの role を定義する必要があるとやや煩雑になります。
Rails4.0に含まれる strong_parameters について - willnet.in
GitHub、Mass Assignment利用の脆弱性を突かれるという事例が発生したので
この煩雑な role 設定の管理をしなくてはいけない状況をどうにかするべく
Strong Parameters が導入されたようです。
Rails4 の Mass Assignment 脆弱性対策の Strong Parameters について
rails generate scaffold user name:string email:stringscaffold を使用すると、Strong Parameters の機能を使用したコードが生成されます。
class UsersController < ApplicationController ... # POST /users # POST /users.json def create @user = User.new(user_params) ... end ... private ... # Never trust parameters from the scary internet, only allow the white list through. def user_params params.require(:user).permit(:name, :email) end endこのコードは「params が :user というキーを持ち、params[:user] は :name 及び :email というキーを持つハッシュであること」を検証します。
例えば、params[:user]が{:name => 'taro', :email => 'taro@example.com'}のようなハッシュである場合に検証 OK となります。
» Rails4 の Strong Parameters でリクエストパラメータを検証する TECHSCORE BLOG
許可していないパラメータが渡された場合はデフォルトでは無視される
試しに user_params の内容を以下のように修正してみます。
# Never trust parameters from the scary internet, only allow the white list through. def user_params # 試に :email の指定を消す. # params.require(:user).permit(:name, :email) params.require(:user).permit(:name) endこの状態で再度ユーザ登録を行うと、リクエストパラメータとして名前(name)とメールアドレス(email)が渡されますが、メールアドレス(email)は無視されます。
ログを確認すると以下のようなメッセージが出力されていました。
Unpermitted parameters: email» Rails4 の Strong Parameters でリクエストパラメータを検証する TECHSCORE BLOG
許可しないパラメータが渡された場合に例外を発生させる
許可しないパラメータが渡された場合の動作は config/application.rb で変更することができます。
試に例外を発生させるように変更してみます。
# デフォルトは :log で, 許可されていないパラメータは無視されたうえでログ出力されます. config.action_controller.action_on_unpermitted_parameters = :raiseこの状態で再びユーザ登録を行うと(リクエストパラメータに name と email が渡されると)、ActionController::UnpermittedParameters という例外が raise されました。
» Rails4 の Strong Parameters でリクエストパラメータを検証する TECHSCORE BLOG
ネストしたパラメータ
Strong Parameters のドキュメントを読むと、permit メソッドの引数を以下のように指定することで、
ネストしたパラメータに対応することができるようです。
params.permit(:name, {:emails => []}, :friends => [:name, {:family => [:name]}])» Rails4 の Strong Parameters でリクエストパラメータを検証する TECHSCORE BLOG
全てのパラメータを許可する
開発中のときなど、全ての属性を許可したいケースがあると思いますが、
その時はparams[:user].permit!のようにします。
ただ、permit!が今のバージョン(0.1.4)だと再帰的に効かないという話しがあるので
(RailsCastsで言ってた。未確認)、うまくいかない場合は github 上の最新を使ってみてください。
Rails4.0に含まれる strong_parameters について - willnet.in
参考
Rails4.0に含まれる strong_parameters について - willnet.in» Rails4 の Strong Parameters でリクエストパラメータを検証する TECHSCORE BLOG
参考というより引用元です。
どちらの記事も読み返したくなる記事内容で Chrome のタブを閉じることができなかったので
内容の9割以上が引用でしたが、記事にすることでタブを閉じることができそうです。
Rails やるときにまた見に行くと思います。
どちらもわかりやすい記事をありがとうございます。