web-dev-qa-db-fra.com

API Rails 5 protect_from_forgery

J'ai une application API Rails 5 (ApplicationController < ActionController::API). La nécessité d'ajouter un simple formulaire d'interface graphique pour un noeud final de cette API est apparue. 

Au début, j'obtenais ActionView::Template::Error undefined method protect_against_forgery? lorsque j'ai essayé de rendre le formulaire. J'ai ajouté include ActionController::RequestForgeryProtection et protect_from_forgery with:exception à ce terminal. Ce qui a résolu le problème comme prévu. 

Cependant, lorsque j'essaie de soumettre ce formulaire, je reçois: 422Unprocessable EntityActionController::InvalidAuthenticityToken. J'ai ajouté <%= csrf_meta_tags %> et vérifié que meta: csrf-param et meta: csrf-token sont présents dans mes en-têtes et que authenticity_token est présent dans mon formulaire. (Les jetons eux-mêmes sont différents les uns des autres.)

J'ai essayé, protect_from_forgery prepend: true, with:exception, sans effet. Je peux "résoudre" ce problème en commentant: protect_from_forgery with:exception. Mais je crois comprendre que cela désactive la protection des CSRF dans mon formulaire. (Je veux une protection CSRF.)

Qu'est-ce que je rate? 

METTRE À JOUR:

Pour que ce soit clair, 99% de cette application est une API JSON RESTful pure. La nécessité d'ajouter une vue HTML et un formulaire à cette application est apparue. Donc pour un contrôleur, je veux activer la protection CSRF complète. Le reste de l'application n'a pas besoin de CSRF et peut rester inchangé.

MISE À JOUR 2:

Je viens de comparer la source de la page du formulaire HTML et de l'en-tête de cette application avec une autre application Rails 5 conventionnelle que j'ai écrite. Le authenticity_token dans l'en-tête et le authenticity_token dans le formulaire sont identiques. Dans l'application API avec laquelle je rencontre un problème, ils sont different. Peut-être que c'est quelque chose?

MISE À JOUR 3:

Ok, je ne le fais pas la disparité est la question. Cependant, lors de comparaisons ultérieures entre les applications actives et non actives, j'ai constaté qu'il n'y avait rien dans Réseau> Cookies. Je vois un tas de choses comme _my_app-session dans les cookies de l'application active.

14
lostphilosopher

Voici le problème: Rails 5, en mode API, n'inclut pas logiquement le middleware Cookie. Sans lui, il n'y a pas de Session key stockée dans un cookie à utiliser lors de la validation du jeton que j'ai transmis avec mon formulaire. 

De manière quelque peu déroutante, changer les choses dans config/initializers/session_store.rb n'a eu aucun effet. 

J'ai finalement trouvé la réponse à ce problème ici: Ajout du magasin de sessions de cookies à l'application Rails API , qui m'a conduit ici: https://github.com/Rails/rails/pull/28009/files qui mentionnait exactement les lignes que je devais ajouter à application.rb pour récupérer les cookies:

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

Ces trois lignes associées à:

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

Et bien sûr, un formulaire généré par les assistants appropriés:

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

M'a obtenu un formulaire protégé par CSRF au milieu de mon application API Rails.

15
lostphilosopher

Si vous utilisez le mode API Rails 5, vous n'utilisez pas protect_from_forgery ni n'incluez <%= csrf_meta_tags %> dans aucune vue, car votre API est "sans état". Si vous envisagiez d'utiliser des Rails complets (pas le mode API) tout en l'utilisant ÉGALEMENT comme API REST pour d'autres applications/clients, vous pouvez procéder de la manière suivante:

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

Donc, ce protect_from_forgery serait appelé le cas échéant. Mais je vois ActionController::API dans votre code, ce qui indique que vous utilisez le mode API, auquel cas vous supprimez la méthode de votre contrôleur d'application. 

8
Ricky Brown

Pas besoin de protect_from_forgery pour les appels et les apis AJAX.

Si vous voulez le désactiver pour une action, alors

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

Utilisez comme ci-dessus avec Rails 5

0
Muktesh Kumar