フレームワーク別
Ruby on Railsのセキュリティ対策 — 本番ハードニング実務リファレンス
Ruby on Railsを安全に運用するための実務リファレンス。優先度つきハードニング・チェックリスト、秘密とcredentials・本番設定・gem(依存)のCVE・Strong Parameters/Mass Assignment・認可・インジェクションと危険メソッド・セッション/CSRF・SSRF/アップロードの各対策、そして自己検証まで。攻撃手順は載せず防御と点検のみ。
対象:Ruby on Railsでアプリを運営している人。ここでは攻撃手順は扱わず、本番を固めるための実務リファレンス(優先度つきチェックリスト・領域別対策・自己検証)を示します。フレームワーク全体の考え方は フレームワーク別セキュリティの入口 も参照。
優先度つきハードニング・チェックリスト
まずこの表を上から実施します。P0は前提、P1が最頻の事故源、P2は継続的な運用衛生です。
P0 ── 前提(まずこれ)
秘密とcredentialsの安全管理 / 本番設定(例外非露出・force_ssl)/ gem CVE即パッチ
P1 ── 最頻の事故源
Strong Parameters/Mass Assignment制御 / 認可(所有者スコープ)
P2 ── 運用衛生
インジェクションと危険メソッド / セッション・CSRF / SSRF・アップロード
| 優先 | 対策 | 具体(Rails) |
|---|---|---|
| P0 | 秘密とcredentials | 暗号化 credentials+master keyを分離。master key をコミットしない。secret_key_base 漏洩はローテーション |
| P0 | 本番設定 | 例外詳細を外部に出さない・config.force_ssl・filter_parameters で機微をログ非記録 |
| P0 | gem(依存)CVE | bundler-audit / osv-scanner で監視・実稼働版で判定し即パッチ |
| P1 | Strong Parameters | permit を必要最小限に。permit! で全許可しない。権限フィールドを代入させない |
| P1 | 認可を明示 | Pundit / CanCanCan+authorize+current_user スコープで所有者確認 |
| P2 | インジェクション/危険メソッド | where はバインド。send/constantize に入力を渡さない。信頼できない YAML/Marshal を読まない |
| P2 | セッション/CSRF | protect_from_forgery(既定)・Cookie の secure/httponly/samesite・ログイン時再生成 |
| P2 | SSRF/アップロード | サーバー側取得は許可先限定+内部IP遮断。アップロードは検証し public/ 外に保存 |
1. 秘密と credentials(P0)
- Railsの暗号化 credentials を使い、master key(復号鍵)をリポジトリにコミットしない(環境変数などで注入)。
secret_key_baseは署名/暗号化Cookieやセッションの土台。漏洩したら速やかにローテーション(既存の署名/暗号化が無効化される点に注意)。.envやダンプ・バックアップを公開ディレクトリに置かない(→ 公開ディレクトリに秘密を置かない)。
2. 本番設定(P0)
- 本番では例外の詳細を外部に出さない(
consider_all_requests_localを本番で有効にしない等)。内部構造の露出を減らす。 config.force_sslでHTTPSを強制し、Cookie を secure に。開発用の web console 等を本番で有効にしない。- ログに機微が残らないよう
filter_parametersでパスワード等をフィルタする。
3. 依存(gem)のCVE(P0)
- bundler-audit や osv-scanner で gem の既知CVEを機械監視し、実稼働版(Gemfile.lock)で判定して即パッチ(→ 依存のCVE監視 / CVE対応の実務)。
- Rails と Ruby をサポート対象バージョンに保ち、EOL版を放置しない。
4. Strong Parameters と Mass Assignment(P1)
permitする項目を必要最小限にし、permit!(全許可)を避ける。is_adminのような権限フィールドをユーザー入力から代入させない。「面倒だから広く許可」をやめる。
5. 認可(P1・最多の事故源)
やりがち(危険)
- 認可を書かず「ログイン=閲覧/更新可」
- ルートモデル束縛で他人のIDでも取得できる
- 隠しただけのルート/推測しにくいIDに依存
- 一部アクションで authorize を通し忘れ
正しい
- Pundit / CanCanCan で方針を明示+各アクションで
authorize - 取得も
current_userのスコープで所有者に限定 - 取得・更新・削除のすべての経路で確認
- 認可は明示的に組み立て、既定任せにしない
用語は IDORとは。認証と認可は別物で、認可はデータに近い場所で確認します。
6. インジェクションと危険な動的メソッド(P2)
- SQL:
whereはプレースホルダでバインドし、文字列連結でクエリを組まない(where("... #{params}")を避ける)(→ SQLインジェクションとは)。 - 危険な動的メソッド:
send/public_send/constantizeにユーザー入力を渡さない。渡すなら許可リストで厳しく限定する。 - デシリアライズ:信頼できない
YAML/Marshalの読み込みは条件次第でコード実行に繋がり得るため避ける。
7. セッション・Cookie・CSRF(P2)
- **CSRF保護(
protect_from_forgery)**を全体無効化しない。フォームのトークンを活かす(→ CSRFとは)。 - Cookie/セッションに secure/httponly/samesite を設定し、ログイン時にセッションを再生成する。
8. SSRF・アップロード・ヘッダ(P2)
- サーバーがユーザー指定URLを取得する処理は許可先を限定し、内部IP/メタデータへの到達を遮断する(→ SSRFとは)。
- アップロードは種別・サイズを検証し、
public/外に保存して実行権限を与えない。 - セキュリティヘッダを付与(自サイトは セキュリティヘッダ診断 で確認)。
検証:自分のRailsは固められているか
作ったら終わりでなく、点検して初めて完了です。以下は自分の環境に対する防御的な自己チェックです。
秘密が露出/コミットされていないか
master.key がリポジトリに含まれていないこと、.envやダンプがURLで取れないことを確認。本番で例外詳細が出ないか
認可が効くか
依存とヘッダ
bundler-audit/osv がクリーンか、ヘッダ診断で HTTPS/HSTS 等が付くかを確認。当サイトの視点:規約に守られても『認可と依存』は自分の責任
Railsの良い既定は多くのリスクを消しますが、「誰が・何を・してよいか」という認可と依存の鮮度だけは、アプリ固有・運用固有なのでフレームワークが自動で守れません。当サイトが繰り返し見る事故も、凝った攻撃より「認証はあるのに所有者チェックが無い」型が多い。だから守りの重心は、上の表を上から潰し、Strong Parametersを締め、認可を明示し、gemをCVE監視するという地味な徹底にあります。
次に読む
- 入口:フレームワーク別セキュリティ(入口) / Laravelのセキュリティ対策(同じMVC・認可の型が近い)
- 実務:脆弱性(CVE)対応の実務 / 依存のCVE監視 / 公開ディレクトリに秘密を置かない
- 用語:IDORとは / SQLインジェクション / CSRF / SSRF
- ツール:セキュリティヘッダ診断
よくある質問
QRailsで最初にやるべきセキュリティ対策は何ですか?
優先度P0の3つです。(1)秘密を安全に扱う(暗号化された credentials とマスターキーを分離し、master key をリポジトリにコミットしない。secret_key_base は署名/暗号化Cookieの土台なので漏洩はローテーション)、(2)本番設定を固める(例外の詳細を外部に出さない・force_ssl)、(3)gem(依存)のCVEを機械監視し実稼働版で判定して即パッチ。次に Strong Parameters と認可へ進みます。
QStrong Parameters で気をつけることは?
受け入れるフィールドを明示的に許可(permit)し、Mass Assignment(想定外フィールドの一括代入)を防ぎます。危険なのは面倒だからと広く許可すること、そして permit! で全許可すること。permit する項目を必要最小限に絞り、is_admin のような権限フィールドは絶対にユーザー入力から代入させないでください。
Q認可はどう実装すれば安全ですか?
ログイン(認証)に加えて、対象が本当にその利用者のものかという所有者チェックを実装します。Pundit / CanCanCan などで方針を明示し、各アクションで authorize を通し、current_user のスコープでリソースを絞ります。隠しただけのルートや推測しにくいIDに頼らず、取得・更新・削除の各経路で明示的に確認するのが安全です。
Qgem(依存)の脆弱性はどう管理しますか?
bundler-audit や osv-scanner で既知CVEを機械監視し、『実稼働版』で判定して素早くパッチします(Gemfile.lock の実際の版で判断)。Rails 本体と Ruby をサポート対象バージョンに保ち、EOL版を放置しないこと。依存の鮮度は、凝った攻撃より事故を分ける現実的な要因です。
Q危険な動的メソッドとは何ですか?
send / public_send / constantize などにユーザー入力を渡すと、意図しないメソッド呼び出しやクラス解決に繋がり得ます。また Marshal や信頼できない YAML の読み込み(オブジェクトの復元)は、条件次第でコード実行に繋がることがあります。これらにユーザー由来のデータを渡さず、渡す場合は許可リストで厳しく限定します。