100
84

More than 5 years have passed since last update.

Rails4 | 新規・変更機能 | マスアサインメント機能と脆弱性とStrong Parameters

Posted at

Rails4 | 新規・変更機能 | マスアサインメント機能と脆弱性とStrong Parameters

概要

マスアサインメント機能と脆弱性とStrong Parameters

マスアサインメント機能

RailsではDBの更新系処理で複数のカラムを一括で指定できます。

例えば

Person.new(name: 'hoge', age: 24)
person.update(name: 'hoge', age: 24)

など。
この便利な機能をマスアサインメント機能と呼びます。

マスアサインメントを利用する際の注意点

マスアサインメントはハッシュをそのまま利用します。
例えばユーザーからのリクエストは params 変数に Hash として保存されています。

この内容をそのままにマスアサインメント機能を利用して設定していた場合に、
想定していないカラムを更新されてしまう可能性があります。

例えばUserクラスに name, age, admin の3カラムがあり、
adminはユーザーの画面からは更新させない管理者権限だとします。

Userの新規登録処理で、以下のようなコードを書いていた場合、

user = User.new(params[:user])
user.save

不正リクエストなどによってparamsにadminが含まれていた場合、
管理者権限を任意の値に設定されてしまいます。

Rails3 までのマスアサインメント対策

もともとRailsのこの対応策を用意していました。
Model で更新対象のカラムを attr_accessible を利用して設定しておくのです。

class User < ActiveRecord::Base
  attr_accessible :name, :age
end

これで、 name , age しか更新できなくなりました。

このような対策が Rails 側で用意されていたものの、
GitHubがマスアサインメントのセキュリティーホールを作ってしまったため、
クラックされてしまいました。
それを機に、この脆弱性の対策が注目されはじめました。

Rails3 までは Model 側で attr_accessible を利用していましたが
Rails4 では Controller 側で Strong Parameters を用いることでこの問題を防ぎます。

Rails4 のマスアサインメント対策

Rails4 では Controller 側の Strong Parameters でマスアサインメントの脆弱性に対応します。
以下は、scaffold によって生成された Strong Parameters のコードです。

def create
  @person = Person.new(person_params)
  # 略
end

private

# Never trust parameters from the scary internet, only allow the white list through.
def person_params
  params.require(:person).permit(:name, :age)
end

下記のように命名するのが慣例になっています。

def <Model>_params
  params.require(:<Model>).permit(:<カラム名1>, :<カラム名2>)
end

マスアサインメント脆弱性をわざと作って、突破してみる

Person を scaffold します。
Personは name , age , admin を持ちます。

rails g scaffold person name:string age:integer admin:boolean
rake db:migrate

views/people/_form.html.erb から管理者のチェックボックスを削除します。
これで、一見管理者権限を設定できなくなったかのように見えます。

下記を削除

  <div class="field">
    <%= f.label :admin %><br>
    <%= f.check_box :admin %>
  </div>

Railsを起動して、 新規追加画面を開きます。

math1.png

そのまま登録すると下記のようなデータになります。
例えば name = 'tanaka', age = 20 の場合が以下。

$ select * from people;
1|tanaka|20||2014-06-25 23:05:23.666879|2014-06-25 23:05:23.666879

次に、再度新規登録画面を開いて GoogleChrome のデベロッパーツールの
ElementタブでHTMLを直接編集します。
Age の設定をしている DIV タグを選択して、右クリック=>Edit HTMLを選びます。
そして、末尾に下記のHTMLを追加します。

<div class="field">
  <label for="person_admin">Admin</label><br>
  <input name="person[admin]" type="hidden" value="0"><input id="person_admin" name="person[admin]" type="checkbox" value="1">
</div>

すると、下記のように画面にチェックボックスが追加されたのでチェックを有効にして
不正リクエストを送信します。

math2.png

math3.png

追加が成功してしまいました。

math4.png

DBを確認しますが、確かに管理者権限が「t」になっています。

$ select * from people;
1|tanaka|20||2014-06-25 23:05:23.666879|2014-06-25 23:05:23.666879
4|suzuki|19|t|2014-06-25 23:21:41.977131|2014-06-25 23:21:41.977131
100
84
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
100
84