web-dev-qa-db-ja.com

Rails 5 API protect_from_forgery

Rails 5 APIアプリ(ApplicationController < ActionController::API)があります。このAPIの1つのエンドポイントにシンプルなGUIフォームを追加する必要が生じました。

最初は、フォームをレンダリングしようとしたときにActionView::Template::Error undefined method protect_against_forgery?を取得していました。 include ActionController::RequestForgeryProtectionprotect_from_forgery with:exceptionをそのエンドポイントに追加しました。期待どおりにその問題を解決しました。

ただし、このフォームを送信しようとすると、422Unprocessable EntityActionController::InvalidAuthenticityTokenが返されます。 <%= csrf_meta_tags %>を追加し、meta: csrf-parammeta: csrf-tokenがヘッダーに存在し、authenticity_tokenがフォームに存在することを確認しました。 (トークン自体は互いに異なります。)

試してみましたが、protect_from_forgery prepend: true, with:exception、効果はありません。この問題をコメントアウトすることで「修正」できます:protect_from_forgery with:exception。しかし、私の理解では、それは私のフォームでCSRF保護をオフにしているということです。 (CSRF保護が必要です。)

私は何が欠けていますか?

更新:

これを明確にするために、このアプリの99%は純粋なJSON RESTful APIです。このアプリに1つのHTMLビューとフォームを追加する必要が生じました。したがって、1つのコントローラーに対して完全なCSRF保護を有効にしたいと思います。アプリの残りの部分はCSRFを必要とせず、変更せずに残すことができます。

更新2:

このアプリのHTMLフォームとヘッダーのページソースを、私が書いた別の従来のRails 5アプリと比較しました。ヘッダーのauthenticity_tokenとフォームのauthenticity_token aresame。私が問題を抱えているAPIアプリでは、それらはdifferent。たぶんそれは何か?

更新3:

わかりました、私は不一致が問題ではありません。ただし、動作中のアプリと動作していないアプリをさらに比較すると、[ネットワーク]> [Cookies]に何もないことがわかりました。動作中のアプリのCookieに_my_app-sessionのようなものがたくさんあります。

14
lostphilosopher

問題は次のとおりです。Rails 5、APIモードの場合、論理的にはCookieミドルウェアは含まれません。これがない場合、Cookieに保存されるSession keyフォームで渡したトークンを検証するときに使用されます。

やや紛らわしいことに、config/initializers/session_store.rbは効果がなかった。

最終的にここでその問題の答えを見つけました: CookieセッションストアをRails API app に追加し直しました。ここ: https://github.com/Rails/rails/pull/28009/files application.rbに追加する必要がある行を正確に言及しました動作しているCookieを取得するには:

config.session_store :cookie_store, key: "_YOUR_APP_session_#{Rails.env}"
config.middleware.use ActionDispatch::Cookies # Required for all session management
config.middleware.use ActionDispatch::Session::CookieStore, config.session_options

これらの3行は次と結合されます。

class FooController < ApplicationController
  include ActionController::RequestForgeryProtection
  protect_from_forgery with: :exception, unless: -> { request.format.json? }
  ...

そしてもちろん、適切なヘルパーによって生成されたフォーム:

form_tag(FOO_CREATE_path, method: :post)
  ...

Rails APIアプリの途中でCSRF保護フォームを取得しました。

15
lostphilosopher

Rails 5 APIモードを使用している場合、protect_from_forgeryまたは含める<%= csrf_meta_tags %>は、APIが「ステートレス」であるため、どのビューでも表示されます。完全なRails(APIモードではない)を使用する一方で、それをREST他のアプリ/クライアントのAPIとして使用する場合)このような:

protect_from_forgery unless: -> { request.format.json? }

そのため protect_from_forgeryは適切なときに呼び出されます。しかし、ActionController::APIコード内で、APIモードを使用しているように見えます。この場合、アプリケーションコントローラーからメソッドを完全に削除します。

8
Ricky Brown

AJAX呼び出しとAPIの場合、protect_from_forgeryは不要です。

何らかのアクションのためにそれを無効にしたい場合は、

protect_from_forgery except: ['action_name']
3
puneet18
class Api::ApiController < ApplicationController
  skip_before_action :verify_authenticity_token
end

上記と同じようにRails 5

0
Muktesh Kumar