2021年8月23日 現場Rails Chapter6-7 (p.253~258) セキュリティを強化する
Railsの代表的なセキュリティ機能
- StrongParameters
- CSRF対策
- インジェクション対策
Strong Prametersとは
想定通りのパラメータかどうかをホワイトリスト方式(リストにないアプリケーションやプログラムは起動しないよう制限を設け、リストにあるアプリケーションやプログラムのみを実行します。 リストに入っていないものはブロックし、一切使用しないことで危険性を回避する)でチェックする機能。 ※ホワイトリストはブラックリストの逆のものというイメージを持つ。
マスアサイメント機能とは
マスアサイメント機能とは、モデルからインスタンスを生成するときに、インスタンスに複数の属性を一括代入できる機能です。 ざっくり言うと、複数のキーワード引数に値を渡すこと。登録、更新を一括でできてしまう機能をマスアサイメント機能という。 つまり、登録更新処理またはインスタンス生成時(newする時)どちらでも属性を一括代入できる。
Person.new(name: 'hoge', age: 24) person.update(name: 'hoge', age: 24)
DBにないカラムをnewの引数で指定すると、エラーが起こる。
以下の例の場合、Taskオブジェクトを生成する際に、nameとdescriptionという2つの属性に値を一括で代入している。
task = Task.new(name: 'ラーメン食べたい', description: '今すぐ食べたい')
許可される型
Railsガイド Action Controllerの概要 4.5.1 許可済みスカラー値より
params.permit(:id)
- String
- Symbol
- NilClass
- Numeric
- TrueClass
- FalseClass
- Date
- Time
- DateTime
- StringIO
- IOActionDispatch::Http::UploadedFile
- Rack::Test::UploadedFile
「paramsの値には許可されたスカラー値の配列を使わなければならない」=>以下のようにキーに空の配列を対応付けられる
params.permit(id: [])
Strong parametersの基本構文
#controller内定義 private def user_params params.require(:キー(モデル名)).permit(:カラム名1,:カラム名2,・・・).merge(カラム名: 入力データ) end
requireメソッド
params内の特定のキーに紐付く値だけを抽出する事ができます。そのため、引数には取り出したい値のキーを指定する必要があります。requireに設定した値が見つからない場合は、例外を発生させます。
#キー値userに対するデータを抽出したい場合 params.require(:user).permit(・・・略・・・)
permitメソッド
許可された値のみを取得することができます。 そのため、permitメソッドの引数には登録を許可する全てのカラム名を指定しておく必要があります。もし、許可されいないカラムがparams内に存在した場合、そのデータは取得されず無視されます。
#Userモデルに存在するnameおよび、emailカラムのみ入力を受け付けたい場合(他のカラム(admin)は受け付けないたくない) params.require(:user).permit(:name,:email)
mergeメソッド
mergeメソッドを使用することでハッシュ同士を結合することができます。 例えば、paramsに含まれない値をストロングメソッドに加えたい場合などに、ストロングパラメータの後に記述することができます。
#paramsのkeyとvalueに含まれていないものを追加したい場合、mergeを使う params.require(:user).permit(:name,:email).merge(user_id: current_user.id)
↓チェリー本 P163 mergeの例文
h = { us: 'dollar', india: 'rupee'} { japan: 'yen' }.merge(h) #=> {:japan=>"yen", :us=>"dollar", :india=>"rupee"}
一次元ハッシュと2次元ハッシュ
#1次元ハッシュ {key1: value1, key2: value2} #2次元ハッシュ {key1: value1, key2: {key3: value3}} #一次元ハッシュの場合=>URL params.permit(:キー名) # 二次元ハッシュの場合=>モデル params.require(:モデル名).permit(:キー名)
requireとpermitメソッドとmergeメソッドのめっちゃわかりやすい例↓
#keyであるboardのvalueをハッシュの形で指定している。mergeで追加されるのは、boardのvalueの部分。 params.require(:board).permit(:body).merge(user_id: current_user.id) {"body"=>"abc", "user_id"=>5} #=>{board:{body: value1, user_id: value2}}
privateメソッド
privateメソッド配下に記述したメソッドは、クラス外からのアクセスができません。 基本的にストロングパラメータは、クラス外からのアクセスをさせないようにprivateメソッド配下に書く。
CSRF
CSRF攻撃例
攻撃例: Amazon会員の太郎さん。ブラウザ操作でログアウトしていない状況で、悪意あるサイトにアクセスしました。
そこには「こちらをクリックすると懸賞にワンクリックで応募できます」の文字と、ボタンがあり、太郎さんはそのボタンをクリックしました。
しかし、そのボタンはAmazon会員を解約するhref="...../delete"
みたいなURLが仕込まれており、太郎さんは意図せずAmazon会員を解約してしまいました。
Ajax
JavaScriptの値を明示的にRails側に渡したい場合は、jQueryでajaxメソッドを使用するのが良い。(jQuery.ajax())ただし、jQueryをrails-ujsの前に読み込んでおく必要がある。 - 「Rails.ajax()」関数を利用することでトークン付きのAjaxリクエストを行うことが出来る。
Ajaxとは?
JavaScriptでサーバー側との通信を「非同期」で行い、通信結果によって「動的にページの一部だけ書き換える手法のこと」です。JavaScript以外にもXMLやDOMなど「既存の機能」を組み合わせて実現します。
例)twitterのいいね機能 ページ全体の更新を行うのではなく、読み込みたい部分だけの通信を行うことで、いいね部分だけ更新することができる。通信の無駄がない!対して、同期通信は更新をしなくて良い部分も更新してしまうので無駄が多い!
POSTリクエスト
Railsのルーティングの文脈での「DELETE」「PATCH」「PUT」なども、ここでいうPOSTリクエストに該当します。
参照
Railsガイド StrobngParameters https://railsguides.jp/action_controller_overview.html#strong-parameters
【Rails】requireとpermitメソッド https://qiita.com/morikuma709/items/2dc20d922409ae7ce216
【Ruby on Rails】ストロングパラメータって何なの?
https://qiita.com/ozackiee/items/f100fd51f4839b3fdca8
チェリー本p163
pikawakaさんブログ https://pikawaka.com/rails/permit
Railsのセッション管理には何が最適か https://qiita.com/shota_matsukawa_ga/items/a21c5cf49a1de6c9561a
初心者目線でAjaxの説明 https://qiita.com/hisamura333/items/e3ea6ae549eb09b7efb9
Railsガイド 「Rails セキュリティガイド -クロスサイトリクエストフォージェリ (CSRF)-」 https://railsguides.jp/security.html#%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA-csrf
Railsのセッション管理には何が最適か https://qiita.com/shota_matsukawa_ga/items/a21c5cf49a1de6c9561a