Rails:POSTリクエストを行うときにCSRFトークンの信頼性を検証できません


91

私はPOST requestこのように私の地元の開発者に作りたいです:

  HTTParty.post('http://localhost:3000/fetch_heroku',
                :body => {:type => 'product'},)

ただし、サーバーコンソールからはレポートされます

Started POST "/fetch_heroku" for 127.0.0.1 at 2016-02-03 23:33:39 +0800
  ActiveRecord::SchemaMigration Load (0.0ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by AdminController#fetch_heroku as */*
  Parameters: {"type"=>"product"}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 1ms

これが私のコントローラーとルートのセットアップです。とても簡単です。

  def fetch_heroku
    if params[:type] == 'product'
      flash[:alert] = 'Fetch Product From Heroku'
      Heroku.get_product
    end
  end

  post 'fetch_heroku' => 'admin#fetch_heroku'

何をする必要があるのか​​わかりませんか?CSRFをオフにすることは確かに機能しますが、そのようなAPIを作成するときは私の間違いだと思います。

他に必要な設定はありますか?


5
APIの場合、CSRFトークンの検証をオフにすることが一般的に受け入れられています。私は使用しますprotect_from_forgery with: :null_session
dcestari 2016

回答:


110

クロスサイトリクエストフォージェリ(CSRF / XSRF)とは、悪意のあるWebページがユーザーをだまして、ブックマークレットやiframeを使用したり、ユーザーをだますのに十分な視覚的類似性のあるページを作成したりするなど、意図しないリクエストを実行させることです。

RailsのCSRF保護は「古典」のWebアプリケーションのために作られている-それは単に要求が独自のWebアプリから発信という保証の度合いを与えます。CSRFトークンは、サーバーだけが知っている秘密のように機能します。Railsはランダムなトークンを生成し、それをセッションに保存します。フォームは非表示の入力を介してトークンを送信し、RailsはGET以外のリクエストにセッションに保存されているものと一致するトークンが含まれていることを確認します。

ただし、APIは通常、定義上クロスサイトであり、Webアプリ以外で使用することを目的としています。つまり、CSRFの概念全体が完全に適用されるわけではありません。

代わりに、APIキーとシークレットを使用してAPIリクエストを認証するトークンベースの戦略を使用する必要があります。これは、リクエストが独自のアプリからではなく、承認されたAPIクライアントからのものであることを確認するためです。

@dcestariで指摘されているように、CSRFを非アクティブ化できます。

class ApiController < ActionController::Base
  protect_from_forgery with: :null_session
end

更新しました。Rails 5では、次の--apiオプションを使用してAPIのみのアプリケーションを生成できます。

rails new appname --api

これらには、CSRFミドルウェアやその他のすばらしいコンポーネントは含まれていません。


おかげで、私はオフCSRFの一部を回すために選択します。stackoverflow.com/questions/5669322/...
cqcn1991

4
これは、すべてのAPIがアプリケーション間トラフィック(単一のパートナーに一意のキーとシークレットが発行される)を処理することを示しています。そのシナリオでは、サーバー間の通信のように、この答えは適切です。ただし、ほとんどのWebアプリ開発者を混乱させるのは、ユーザーが制御および作成するJavascriptクライアントの場合、単一のキーシークレット(すべてのクライアントに単一のキーシークレットを公開する)を使用したくないということです。代わりに、RailのCSRFとCookieセッションメカニズムは、APIを使用するJavascriptアプリの場合でも、リクエストごとにCSRFトークンをRailsに返すとうまく機能します。
ジェイソンFB19年

あなたはAJAXでこれを行う方法は、このSO記事で説明されてstackoverflow.com/questions/7203304/...
ジェイソンFB

@JasonFBは、javascriptクライアントの単一のシークレットが機能しないという点で正しいです。ただし、他のタイプの非ブラウザークライアントでも使用できるAPIを構築する場合は、セッションとRailsCSRF保護の使用には依然として問題があります。
最大

CSRFに代わるものを提供または構築する場合は、私のゲストになります。何を交換するのが適切かがわかるように、交換する理由を知ってください。明らかに、今、私たちの口論は文脈的になります。
ジェイソンFB19年

78

nullセッションをレンダリングしないCSRFをオフにする別の方法は、次を追加することです。

skip_before_action :verify_authenticity_token

Railsコントローラーで。これにより、セッション情報に引き続きアクセスできるようになります。

繰り返しになりますが、これはAPIコントローラーまたはCSRF保護が完全に適用されない他の場所でのみ行うようにしてください。


1
これはprotect_from_forgery except: [:my_method_name]?と同じです
アーノルドロア

19

api.rubyonrails.orgのAPIコントローラーに関するCSRFの構成に関する関連情報があります。

XMLまたはJSONリクエストも影響を受けることを覚えておくことが重要です。また、APIを構築している場合は、次のように偽造保護方法を変更する必要ApplicationControllerがあります(デフォルトでは:) :exception

class ApplicationController < ActionController::Base
  protect_from_forgery unless: -> { request.format.json? }
end

APIは通常ステートレスになるように設計されているため、APIのCSRF保護を無効にすることをお勧めします。つまり、リクエストAPIクライアントがRailsの代わりにセッションを処理します。


4
これはとても紛らわしいです。私は言うソース間で一進一退していますprotect_from_forgery、それはないと言うことなAPIのために依然として必要である、とソース。APIがユーザー認証にセッションCookieを使用するシングルページアプリ用である場合はどうなりますか?
Wylliam Judd 2018

CSRFメカニズムは、セッションCookieを使用して攻撃ベクトルを処理するRailsの組み込みの方法です。このメカニズムは、RailsセッションCookieと一緒に(実際には内部で)動作しながら、コントローラーを保護します。protected_from_forgeryがない場合、またはオフにするか、例外を設定しない場合、CSRFトークン(セッションCookieから取得)からの情報を使用してそのアクションを保護しないようにRailsに指示します。
ジェイソンFB19年

5
紛らわしいのは、Railsのドキュメントでは、「API」とは、信頼できるリモートパートナー(サイトにアクセスするすべてのWebユーザーではない)からAPIリクエストを受信するサーバー間アプリケーションを意味することだと思います。それらのpplには、ハッキングできない安全なメカニズムを介して一意のキーとシークレットのペアを提供します。多くの人がWebクライアントを介してWebアプリをロードする、最新のWebアプリケーションの場合でも、セッションまたはトークンベースのメカニズムを使用して、サイトにアクセスする各人を一意に識別します。したがって、これを行うために他のメカニズム(Json Webトークンなど)を使用していない限り、Railsの組み込みのものを使用してください。
ジェイソンFB19年

1
あなたはAJAXでこれを行う方法は、このSO記事で説明されてstackoverflow.com/questions/7203304/...
ジェイソンFB

13

Rails 5以降、:: Baseの代わりに:: APIを使用して新しいクラスを作成することもできます。

class ApiController < ActionController::API
end

3

サンプルコントローラーのサンプルアクションを除外する場合

class TestController < ApplicationController
  protect_from_forgery :except => [:sample]

  def sample
     render json: @hogehoge
  end
end

外部からのリクエストも問題なく処理できます。


0

この問題の最も簡単な解決策は、コントローラーで標準的なことを行うか、直接ApplicationControllerに入れることです。

class ApplicationController < ActionController::Base protect_from_forgery with: :exception, prepend: true end


0

(コントローラー全体ではなく)1つ以上のコントローラーアクションのCSRF保護のみをスキップする場合は、これを試してください

skip_before_action :verify_authenticity_token, only [:webhook, :index, :create]

[:webhook, :index, :create]これらの3つのアクションのチェックはどこでスキップされますが、スキップしたい方に変更できます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.