1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】【エラー解説】APIモードでprotect_from_forgeryが使えない理由と対処法

1
Posted at

はじめに

この記事は、RailsのAPIモードで「protect_from_forgery」エラーが発生した場合の原因と対処法を解説します。

この記事でわかる・できること

  • エラー発生の仕組み(protect_from_forgeryがNoMethodErrorになる理由)
  • CSRFとXSSとAPI認証の関係
  • APIモードでの安全な運用方法
  • 解決方法

この記事の対象者

  • Rails API(--api)モードを使う開発者
  • SPA/モバイルアプリのバックエンドAPI開発者
  • RailsのCSRFやXSS対策に疑問がある人

動作環境・使用するツールや言語

  • OS バージョン: macOS Sequoia 15.5
  • ツール: VSCode 1.102.1
  • 言語: Ruby 3.4.4 / Rails 8.0.2
  • 認証ツール: Firebase Auth
  • フレームワーク: Rails APIモードなど

エラーの原因とWeb/APIの違い

エラーの内容

NoMethodError (undefined method 'protect_from_forgery' for class Api::SuggestionsController)

原因

APIモードのRailsアプリは、protect_from_forgeryを持つActionController::Baseではなく、ActionController::APIを継承しています。
そのため、CSRF保護機能自体が存在しませんというエラーが発生します。

このエラーの詳細

通常のWebアプリはCookieベースのセッション認証+CSRF対策が必須。
RailsのAPIモードは「トークン認証(JWT等)」が基本です。
私は、Firebase AuthのJWTを使用していました。
トークン認証だとCookieを自動送信しないためCSRFリスクがほとんどないと言われています。

解決方法

① 該当行を削除する

APIコントローラから下記を完全に削除してOKです。

protect_from_forgery with: :null_session

② どうしてもprotect_from_forgeryを使いたいとき

Webコントローラ(ActionController::Base継承)へ切り替えて運用します。
しかし通常のAPI連携には不要なので、SPA+API+トークン認証なら削除してOKです。

トークン認証方式でCSRF対策が不要な理由

CSRF(クロスサイトリクエストフォージェリ)とは?

「Cookieベースの認証セッション」+「リクエストを外部サイトから自動送信」できることにより成立する攻撃です。

APIはトークン認証が前提

JWT・BearerトークンなどはCookie経由では送信せず、明示的にヘッダーなどでトークンを付与します。
ブラウザが外部サイトからAPIに勝手にトークンを送ることができないので、CSRFはほとんど発生しません。
詳しくは以下のサイトをご覧ください。

APIモードにおけるXSS対策は必要か?

XSS(クロスサイトスクリプティング)とは?

「Webページの入力フィールドやデータ表示領域に悪意のあるJavaScript等のコードを埋め込むことで、ユーザーのブラウザ上で不正な動作を実行させる攻撃手法」です。

ユーザーがコメント欄などにJavaScriptコードを投稿したとき、サイト側がサニタイズせずそのまま表示した場合、コメント欄を見た他ユーザーのブラウザでそのコードが実行されます。

一般的に、JWTなどのトークンはクライアント側に一時保存されて、UXの向上を図っています。
このトークンの保管場所でXSSリスクが変わると言われてます。

トークンの代表的な保存場所とXSSリスク

1. localStorage

JavaScriptで簡単に読み書きできるキー・バリュー型ストレージで中身のデータはブラウザを閉じても消えません。XSS攻撃でJSから簡単に盗まれるリスクがあります。

2. sessionStorage

ローカルストレージと似ていますが“タブ/セッションごと”に管理されるので、ブラウザを閉じるとデータが消えます。ただし、localStorage同様XSS耐性は小さいと言われています。

3. Cookie

サーバーとの通信時に自動で送信でき、httpOnly属性を付ければJSからの盗難を防ぎやすいです。
secure属性でHTTPS限定送信にできる点も魅力的。
そのため、httpOnly属性ならXSS耐性が強く、サーバ側で自動的・確実に取得できます。
ただし、Cookieで送信すると「CSRF攻撃の可能性」が再び生じます(CSRF対策必須)。

4. IndexedDB

より高度なクライアントサイドデータベースで、localStorageよりもXSS耐性が強いです。
IndexedDB は Javascript から読み取れるが、バイナリ構造でXSS攻撃の難易度が比較的高いと言われています。
Firebase Auth の JWT は IndexedDB に保存されています。

どこが推奨?

最も安全なのは、CookieのhttpOnly属性付き保存(ただしCSRF対策必須)です。
CSRFトークンやSameSite属性(Strict, Laxなど)などを使って、CSRF対策も行いましょう。

ただし、SPAで簡易運用ならXSS対策を万全にして、LocalStorageやIndexedDBなどに保存することも可能です。
その場合は、以下の3点を行いましょう。

  • エスケープ処理やサニタイジング(React なら JSX がデフォルトで防御)
  • 外部データを直接 HTML に入れない
  • CSP(Content Security Policy)

まとめ表

保存場所 XSS耐性 CSRF耐性 サーバ自動送信 備考
localStorage なし JSから奪われやすい
sessionStorage なし 一時的(JSアクセス可)
Cookie 強(※) あり httpOnly属性でJSアクセス不可、CSRFリスク残る
IndexedDB なし JSでアクセス可(バイナリ構造でXSSリスクが相対的に低い)

※CookieのXSS耐性はhttpOnly属性を使った時のみ

参考資料

おわりに・まとめ

  • APIモードのRailsではCSRF機能が省略され、protect_from_forgeryは不要
  • 基本的にはAPIはトークン認証を使い、CSRFリスクは非常に低い
  • 例外的にCookie認証を使うAPIではCSRF対策が必要となることもある
1
0
0

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?