ja ja ja en ja en ja ja zh ja ja ja ja en ja ja ja ja ar ja ja ja ja ja ja ja ja en ja hi ja ja ja ja ja ja en ja en ja ja en ja ja en ja ja en ja en zh ja en nl ja de ja ja sv ja ja nb ja ja en ja ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja cv es es ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja
Rails4.0に含まれる strong_parameters について - おもしろwebサービス開発日記
strong_parameters とは、mass assignment で余計なパラメータをモデルの属性にセットさせないための新しい仕組みです。Rails 4.0 からはこれが標準になります。Rails2.x と 3.x はattr_accessibleやattr_protectedなどで似たような機能が提供されていましたが、これだと管理が煩雑になるケースがありました。
今年の3月くらいにGitHub が mass assignment の脆弱性を突かれたことで 、この問題をどうにかしようという流れが起き、最終的に strong_parameters が作られるという経緯を辿りました。
def create @user = User.new(params[:user]) unless @user.save render 'new' end end
Userモデルにnameとemailという属性が設定されていて、params[:user]に{name: 'willnet', email: 'willnet@example.com'}のようなパラメータが入っていたとき、上記のUser.new(params[:user])で一度にnameとemailが設定されます。これが mass assignment です。属性が多いときなど大変便利です。
さて、 それでは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
上記のコードは基本的にはうまく動くはずです。ただしユーザが普通にブラウザを使う限りは。
chromeのデベロッパーツールなどで などのタグをform中に生成してsubmitする
curlやtelnetなどで直接user[token]=hogeのようなリクエストを、通常のリクエストに追加して送信する
上記のような方法を使った場合、ユーザに編集させたくないtoken属性が更新されてしまいます。これが mass assignment の脆弱性と呼ばれるものです。
Rails2.x と 3.0系の mass assignment 脆弱性対策
attr_accessibleやattr_protectedが提供されていました。Rails2系(および3.0)だと後述のroleが設定できないため、例えばUser#nameだけ更新したい場合とUser#nameとUser#email両方を更新させたい場合の2種類があるケースなど、同じモデルに複数種類の mass assignment 脆弱性対策をかけたくなります。ただこの頃はそのような機能が提供されておらず、そのため個人的にはこの頃のattr_accessibleやattr_protectedは全く使っていませんでした。そのころは更新させたい属性の配列を定義しておいて手動でparamsをフィルタリングするようなことをしていました。
Rails 3.1 以上からの mass assignment 脆弱性対策
attr_accessibleやattr_protectedに role という機能が導入されました。
class User < ActiveRecord::Base attr_accessible :name attr_accessible :name, :email, as: :name_and_email end
as オプションで role の名前を指定して、
@user.update_attributes(params[:user], role: 'name_and_email')
のように role オプションで適用したいattr_accessible(もしくはattr_protected)を指定します。role がない場合はデフォルトのもの(上記のケースはattr_accessible :name)が使用されます。
これにより大分きちんと書けるようになったのですが、多くの role を定義する必要があるとやや煩雑になります。
Rails 4.0 時代の mass assignment 脆弱性対策(strong_parameters)
Rails 4.0 からは基本の機能になるようですが、gem として使うことで 3.1 や 3.2 でも使うことができます。
github上の README にも書いてありますが、普通にGemfileに書いてbundle install。あとは使用したいモデルで下記のモジュールをincludeすればOKです。
class User < ActiveRecord::Base include ActiveModel::ForbiddenAttributesProtection end
また、config/application.rbに下記の設定が true になっている場合は false に変更します。
config.active_record.whitelist_attributes = false
下記のように使います。
def update @user = User.find(params[:id]) permitted_params = params.require(:user).permit(:name, :email) unless @user.update_attributes(permitted_params) render 'edit' end end
permit の行をコメントアウトすると、ActiveModel::ForbiddenAttributesの例外が発生します。permit メソッドの引数として指定された属性は mass assignment を許可されます。指定されなかった属性が params に入っている場合はフィルタリングされ、モデルには渡りません。
require メソッドは、そのパラメータがないと例外を吐くメソッドです。実際のコードを見た方が理解が早いかもしれません。
def require(key) self[key].presence || raise(ActionController::ParameterMissing.new(key)) end
開発中のときなど、全ての属性を許可したいケースがあると思いますが、その時はparams[:user].permit!のようにします。ただ、permit!が今のバージョン(0.1.4)だと再帰的に効かないという話しがあるので(RailsCastsで言ってた。未確認)、うまくいかない場合は github 上の最新を使ってみてください。
nested parameters にも対応しているようです(未確認)。README をみたところ下記のような感じで書けるようです。
params.permit(:name, friends: [ :name, { family: [ :name ] }])
また、 strong_paramters を入れた状態で scaffold をしたら下記のアクションが生成されていました。なかなか気が利く感じですね。
# Use this method to whitelist the permissible parameters. Example: # params.require(:person).permit(:name, :age) # Also, you can specialize this method with per-user checking of permissible attributes. def user_params params.require(:user).permit(:email, :name, :token) end
attr_accessibleやattr_protectedよりもスマートに書けると思うので、Rails 3.1 と 3.2 を使っている人は導入してみると良いのではないでしょうか。
willnet 2012-10-26 00:59
turbolinksとform_withを便利に使うためのgemを作った
前提 rails標準のわりに使っている人の少ないturbolinksですが…
Rails で fat model を避けるための、あまり知られていない方法について
このエントリで書いた内容は、ほぼ Growing Rails Applications…
ginza.rb 第1回を開催して strong_parameters のソースコードを読んだ
7月16日(火)に ginza.rb 第1回を開催しました。 Ginza.rb 第1回…
エラー通知用ウェブサービス airbrake のメモ
エラー通知用のウェブサービス Airbrake の ruby 用プラグイン …
Rails 3 の Action Mailerまとめ
Ruby on Rails Guides: Action Mailer Basicsを読んでの自分用…
« mac のターミナルのタブをCtrl-TABで切り… リーダブルコードを読んだ »
id:willnet はてなブログPro
べんりで楽しいwebサービスをたくさん作りたい
読者です 読者をやめる 読者になる 読者になる
@netwillnetをフォロー
失敗したテストのログだけを出力するぞ
iCARE Dev Meetup #34で登壇しました
`Thread.current[:hoge]`はスレッドローカル変数を参照していると思いきや実際はファイバーローカル変数だった