web-dev-qa-db-fra.com

Rails: Impossible de vérifier l'authenticité du jeton CSRF lors de la création d'une POST demande

Je veux faire POST request à mon dev local, comme ceci:

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

Cependant, à partir de la console du serveur, il indique 

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

Voici mon contrôleur et la configuration des routes, c'est assez simple. 

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

  post 'fetch_heroku' => 'admin#fetch_heroku'

Je ne suis pas sûr de ce que je dois faire? Désactiver le CSRF fonctionnerait certainement, mais je pense que cela devrait être mon erreur lors de la création d'une telle API.

Y at-il une autre configuration que je dois faire?

49
cqcn1991

La falsification des références entre sites survient lorsqu'une page Web malveillante incite les utilisateurs à exécuter une requête qui n'est pas destinée, par exemple, à l'aide de bookmarklets, d'iframes ou simplement en créant une page qui est visuellement assez similaire pour duper les utilisateurs.

La protection CSRF de Rails est conçue pour les applications Web "classiques". Elle garantit simplement que la demande provient de votre propre application Web. Un jeton CSRF fonctionne comme un secret que seul votre serveur connaît: Rails génère un jeton aléatoire et le stocke dans la session. Vos formulaires envoient le jeton via une entrée masquée et Rails vérifie que toute demande non GET inclut un jeton qui correspond à ce qui est stocké dans la session.

Cependant, une API est généralement, par définition, multisite et doit être utilisée dans davantage que votre application Web, ce qui signifie que le concept de CSRF n’est pas tout à fait applicable.

Au lieu de cela, vous devez utiliser une stratégie basée sur un jeton consistant à authentifier les demandes d'API avec une clé d'API et un secret puisque vous vérifiez que la demande provient d'un client d'API approuvé - et non de votre propre application.

Vous pouvez désactiver CSRF comme indiqué par @dcestari:

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

Mis à jour. Dans Rails 5, vous pouvez générer des applications utilisant uniquement l'API à l'aide de l'option --api

Rails new appname --api

Ils n'incluent pas le middleware CSRF et de nombreux autres composants qui sont superflouus. 

68
max

Un autre moyen de désactiver CSRF sans rendre de session nulle consiste à ajouter:

skip_before_action :verify_authenticity_token dans votre contrôleur Rails. Cela garantira que vous aurez toujours accès aux informations de session. 

Encore une fois, veillez à ne le faire que dans les contrôleurs d'API ou dans d'autres endroits où la protection CSRF ne s'applique pas tout à fait. 

38
Matt Waldron

Il existe des informations pertinentes sur une configuration de CSRF en ce qui concerne les contrôleurs API sur api.rubyonrails.org :

Il est important de noter que les requêtes XML ou JSON sont également affectées. Si vous créez un API , vous devez modifier la méthode de protection contre la falsification dans ApplicationController (par défaut: :exception):

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

Nous souhaitons peut-être désactiver la protection CSRF pour les API car elles sont généralement conçues pour être sans état. En d’autres termes, la requête API client gérera la session pour vous au lieu de Rails.

9
Mr. Tao

Dans Rails 5, vous pouvez également créer une nouvelle classe avec :: API au lieu de :: Base:

class ApiController < ActionController::API
end
1
webaholik

Si vous souhaitez exclure l'exemple d'action du contrôleur

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

  def sample
     render json: @hogehoge
  end
end

Vous pouvez traiter les demandes de l'extérieur sans aucun problème.

0
Ryosuke Hujisawa