【2026.09.23 追記】
読者の方からのご指摘を受け、「3.privateメソッド」の解説文をより正確な内容(処理の共通化と非公開スペースとしての役割)に修正しました。コメントをくださった@scivolaさん、ありがとうございます!
未経験からプログラミング学習に励んでおります。
楽しいこと大好き、自由を求める『Tatooo』です。
現在Railsの学習中ですが、先日RUNTEQのイベントでオンラインLT会がありまして、初めての登壇を経験しました。内容は、アプリのセキュリティを高める機能『Strong Parameters』について、税関職員に例えてみるというものです。今回はその内容を備忘録として記事にしておきたいと思います。
※この記事は超初心者向けなので、ご注意ください。
アプリの平和を守る税関職員の存在 🐾
皆さんは、海外旅行の帰りに税関検査を受けたことがありますか?もしくは某テレビ番組(「世界なんちゃらテレビ」や「突破なんちゃら」)で税関検査の様子を見たことはないでしょうか?
旅行者のスーツケースの中に麻薬や拳銃などの違法なものが入っていないか、スーツケースが二重底になっていないかと目を光らせて、国内に怪しいものを持ち込ませないよう検査をしている職業。それが税関職員になります。
そんな税関職員が、実はアプリのプログラミングコードの中にも存在します。
class UsersController < ApplicationController
# ・・・省略・・・
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
このコントローラー内に記述されているuser_paramsという、独自に定義されたメソッドです。
ここで使われているrequireやpermitといった仕組みを総称して『Strong Parameters』といい、アプリの重要なセキュリティ機能を担っています。
では具体的にどういう機能なのか、税関検査の例えで説明していきます。
1.ブラウザ=海外、アプリ=国内
データはブラウザからアプリへと入ってきますが、ブラウザには安全なデータだけでなく、悪意あるデータが存在しています。そして、当然アプリ内にそのデータを入れないようにしなければなりません。海外から国内へ怪しいものを持ち込ませてはならないということです。
2.HTTPリクエスト=旅客、Params=スーツケース
ブラウザで入力して送信されたデータはParamsというデータの箱(厳密にはActionController::Parametersという特殊なオブジェクト)にまとめられます。さらにこのParamsは、POSTやPATCHというHTTPリクエストを通して運ばれます。海外でスーツケースに荷物を詰めて、そのスーツケースを旅客が運んでくるというイメージです。
3.privateメソッド=職員専用の税関検査場(非公開の処理スペース)
運ばれてきたデータは privateメソッド内に定義された user_paramsでチェックを受けることになります。Railsにおいて、コントローラーのpublicなメソッドは「ブラウザから直接アクセスできる窓口」として機能します。一方でprivateメソッドは、ブラウザから直接アクセスされることのない「アプリ内部の処理だけで使う、職員専用のスペース」のような場所です。
荷物チェックの処理は、ユーザーの「新規登録」や「情報更新」など、複数の窓口で共通して行われます。そのため、窓口ごとに毎回同じ検査マニュアルを書くのではなく、内部の専用スペース(private)にチェック機能をまとめておき、各窓口から使い回せるようにしているのです。
4.requireメソッド・permitメソッド=税関検査官
ここでStrong Parametersの登場です。最初にrequireメソッドが機能して、送られてきたデータの中に user という名前の荷物(キー)がちゃんと存在するかどうかを確認し、その中身を取り出します。そして、permitメソッド内に記述したものと同じデータのみ、安全なものとしてコントローラー内で扱う(モデルに渡す)ことを許可します。
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
# name,email,password,password_confirmationのみデータ登録を許可
# 他のデータ<admin(管理者権限),balance(残高)など>は登録を一切許可しない
税関検査官が最初に荷物タグで誰の荷物かを確認し、その後に通関しても良い物品だけをまとめたリストを確認しながらチェックをします。もしリストにない物品がスーツケースに入っていたら、その物品は没収されます。
この一連の流れを通して、ブラウザから運ばれてきたデータがデータベースに登録しても良いものか、そうでないかをチェックしています。
もしStrong Parametersがなかったらどうなる? 🐾
なぜこの機能が重要なのかというと、もし悪意あるユーザーがブラウザの検証ツールなどをいじって、勝手に user[admin]=true (管理者権限の付与)というようなパラメータを追加して送信してしまうと、一般ユーザーが管理者として登録されてしまい、そのアプリを乗っ取られてしまう可能性があります。
また、balance(残高情報)やpoint(ポイント)といったパラメータが送信されると金銭的被害やデータの整合性破壊につながったり、user_idを別のIDに書き換えて送信されることで他人の投稿を書き換えられる恐れもあります。
このような重大なセキュリティリスクを『マスアサインメント(Mass Assignment)』といいます。
そして、実は皆さんがよく知っているGitHubでも実際にマスアサインメントの脆弱性を突いたハッキング事件が生じています。
2012年3月に発生したハッキング事件 🐾
事件の概要
ロシアのセキュリティ研究者であるEgor Homakov氏が、GitHub(Ruby on Railsで構築されています)の脆弱性を証明するため、公式の「Ruby on Rails」ソースコード管理リポジトリの権限を奪取してみせた事件です。
ハッキングの手口
当時、GitHubの「SSH公開鍵(サーバーへ安全に接続するための鍵)」を登録する機能において、マスアサインメントの対策が漏れていました。
Homakov氏は自分のSSH鍵を登録する際、不正なリクエストを送り public_key[user_id]=(RailsコアチームメンバーのID) というパラメータを意図的に混入させました。
引き起こされた結果
- サーバー側が送られてきた user_id を検証せずにそのままデータベースを更新してしまったため、「Homakov氏の鍵」が「Rails公式開発チームの権限」として紐付いてしまいました
- これにより、Homakov氏は本来部外者であるにもかかわらずRails公式リポジトリへの「コミット権限(書き込み権限)」を獲得し、実際にシステムの本番環境(マスターブランチ)へデモンストレーションとしてファイルを送信することに成功しました
この事件が与えた影響(Strong Parametersの誕生)
実はHomakov氏は事前に「マスアサインメントは危険だ」と警告を報告(Issueを作成)していましたが、当時のRails開発陣は「それは開発者側で気をつけるべき問題だ」と取り合っていませんでした。
しかし、世界を代表するRailsアプリであるGitHubですらこの脆弱性を突かれて乗っ取られたことで事態は一変しました。これを重く受け止めたRails開発陣は方針を改め、パラメータの許可リストをコントローラー側で厳格に管理する「Strong Parameters」を開発し、Rails 4から標準機能として導入しました。
つまり、Strong Parameters(税関職員)は、このGitHub乗っ取り事件という「大事件」を教訓にして配備されるようになった、歴史的にも非常に重要なセキュリティ機構と言えます。
若手検査官とベテラン検査官 🐾
ここまでStrong Parametersの基本的な機能や重要性について説明してきました。ここでもう一歩だけ踏み込んでみたいと思います。
先ほど説明したrequireメソッドとpermitメソッドの組み合わせによるデータチェック機能は、いわば若手の税関検査官による検査です。
最新のRailsバージョン(8.0以降)では、Strong Parametersの新しいメソッドとしてexpectメソッドが登場しました。このメソッドは従来のrequireメソッドおよびpermitメソッドを一つにまとめた、よりスマートで安全な書き方になります。
例えるなら、無駄がなくて、より厳格に検査をする経験豊富なベテランの税関検査官です。記述例はこちら。
def user_params
params.expect(user: [ :name, :email, :password, :password_confirmation ])
end
このメソッドを使うことで、以下のようなメリットがあります。
コードがスッキリする
requireとpermitを「.(ドット)」で数珠つなぎ(メソッドチェーン)にする必要がなくなり、ハッシュ形式で書けるため、一目で「誰の、どのパラメータを許可しているか」が直感的にわかりやすくなります。
より厳格で安全(型のチェックが厳しい)
従来のpermitでは、意図せず配列などの予期しないデータ型がすり抜けてしまうようなわずかな隙がありました。しかし、expectでは指定した構造(単一のデータか、配列かなど)に完全一致するものだけを厳格に抽出してくれます。
500エラーを防ぐことができる
悪意あるユーザーが本来「ハッシュ(データの箱)」で送るべきところを「文字列」で送ってきたとします。予期せぬデータが届くと若手の税関検査官はパニックになって500エラーを起こし、アプリ全体に関する重大エラーとしてクラッシュしてしまいます。一方で、ベテランの検査官であるexpectは、データの形式までチェックするので、パニックを起こさずに400エラー(ユーザー側のリクエスト不備)として安全に処理してくれます。
まとめ 🐾
- Strong Parametersはアプリの平和を守る税関職員のようなもの
- マスアサインメント脆弱性の対策で標準搭載されるようになった
- 最新のRails(8.0以降)ではexpectメソッドが誕生
- expectによって、シンプルな記述でより安全性が向上した
以上になります。
最後まで読んでいただきありがとうございました。