Token di autenticità di Rails 4


198

Stavo lavorando su una nuova app Rails 4 (su Ruby 2.0.0-p0) quando ho riscontrato problemi di token di autenticità.

Durante la scrittura di un controller che risponde a JSON (usando il respond_tometodo class), sono arrivato createall'azione che ho iniziato a ottenere ActionController::InvalidAuthenticityTokeneccezioni quando ho provato a creare un record usando curl.

Mi sono assicurato di impostare -H "Content-Type: application/json"e impostare i dati con, -d "<my data here>"ma ancora senza fortuna.

Ho provato a scrivere lo stesso controller usando Rails 3.2 (su Ruby 1.9.3) e non ho avuto alcun problema con i token di autenticità. Ho cercato in giro e ho visto che c'erano dei cambiamenti con i token di autenticità in Rails 4. Da quello che ho capito, non vengono più inseriti automaticamente nei moduli? Suppongo che ciò influisca in qualche modo sui tipi di contenuto non HTML.

Esiste un modo per aggirare questo problema senza dover richiedere un modulo HTML, strappare il token di autenticità e quindi fare un'altra richiesta con quel token? O mi manca completamente qualcosa di completamente ovvio?

Modifica: ho appena provato a creare un nuovo record in una nuova app Rails 4 usando uno scaffold senza cambiare nulla e sto riscontrando lo stesso problema, quindi immagino che non sia qualcosa che ho fatto.

Risposte:


277

Penso di averlo appena capito. Ho modificato il (nuovo) valore predefinito

protect_from_forgery with: :exception

per

protect_from_forgery with: :null_session

come da commento in ApplicationController.

# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.

Puoi vedere la differenza osservando la fonte request_forgery_protecton.rbo, più specificamente, le seguenti righe:

In Rails 3.2 :

# This is the method that defines the application behavior when a request is found to be unverified.
# By default, \Rails resets the session when it finds an unverified request.
def handle_unverified_request
  reset_session
end

In Rails 4 :

def handle_unverified_request
  forgery_protection_strategy.new(self).handle_unverified_request
end

Che chiamerà il seguente :

def handle_unverified_request
  raise ActionController::InvalidAuthenticityToken
end

20
È possibile rimuovere: con l'opzione tutti insieme,: null_session è l'impostazione predefinita: api.rubyonrails.org/classes/ActionController/…
Casey

6
Esiste un modo per utilizzare l'eccezione per le chiamate non JSON e la sessione null per le chiamate JSON (ovvero le chiamate API)?
James McMahon,

@JamesMcMahon Potresti essere in grado di scrivere il tuo before_actionche controlla il formato e se la richiesta è verificata. Non conosco alcun modo integrato per stabilire le condizioni.
alexcoco,

1
In rails 4.1.6, ho dovuto specificare anche skip_before_action :verify_authenticity_tokensul controller dell'applicazione della mia API per farlo funzionare.
Waseem,

1
Non dovresti più disabilitare :verify_authenticy_tokenin Rails 4.2. L'impostazione predefinita è :null_session, che, come suggerisce il nome, ti dà solo una richiesta senza una sessione. Puoi invece verificare la richiesta tramite una chiave API.
lobati,

72

Invece di disattivare la protezione csrf, è meglio aggiungere la seguente riga di codice nel modulo

<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %> 

e se stai usando form_for o form_tag per generare il modulo, aggiungerà automaticamente la riga di codice sopra nel modulo


9
Questo è un buon consiglio se stai compilando un modulo, ma la domanda si riferisce al fare chiamate API usando JSON.
James McMahon,

1
Grazie, però, questo ha risposto a una domanda che avevo riguardo alla scrittura a mano di un codice durante l'utilizzo del manubrio!
David Routen,

70

L'aggiunta della seguente riga nel modulo ha funzionato per me:

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

12
non si applica realmente chiamate API
courtsimas

2
Nel mio caso, sto usando Rails4. Posso inviare il modulo facendo clic sul pulsante di invio. Ma se invio il modulo tramite il codice JS, si verifica questo errore. E questa risposta ha risolto il problema per me.
Chris.Zou,

2
Per la mia app basata su Rails 4.0.8 è stato sufficiente scrivere =token_tag nilo (in .erb)<%= token_tag nil %>
jmarceli

1
Sembra che tu stia disabilitando l'autenticazione impostando il token su zero?
Carlos,

è sicuro farlo?
Angel Garcia,

33

Non penso che sia buono in genere disattivare la protezione CSRF finché non si implementa esclusivamente un'API.

Quando si guarda la documentazione dell'API di Rails 4 per ActionController ho scoperto che è possibile disattivare la protezione dalle contraffazioni su un controller o su un metodo base.

Ad esempio, per disattivare la protezione CSRF per i metodi che è possibile utilizzare

class FooController < ApplicationController
  protect_from_forgery except: :index

Questo lo ha fatto per me in Rails 4 - errore generato dopo aver tentato di eliminare. ^^
zero_cool

9

È venuto attraverso lo stesso problema. Risolto il problema aggiungendo al mio controller:

      skip_before_filter :verify_authenticity_token, if: :json_request?

metodo non definito `json_request? ' per # <SettingsController: 0x000000030a54a8>, Qualche idea?
Deano,

Devi definire un metodo lì come: def json_request? request.format.json? fine
Jai Kumar Rajput,

7

Hai provato?

 protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }



2

Queste funzionalità sono state aggiunte per motivi di sicurezza e protezione dalle contraffazioni.
Tuttavia, per rispondere alla tua domanda, ecco alcuni input. È possibile aggiungere queste righe dopo il nome del controller.

Così,

class NameController < ApplicationController
    skip_before_action :verify_authenticity_token

Ecco alcune linee per diverse versioni di binari.

Rotaie 3

skip_before_filter: confirm_authenticity_token

Rotaie 4 :

skip_before_action: confirm_authenticity_token


Se si intende disabilitare questa funzione di sicurezza per tutte le routine del controller, è possibile modificare il valore di protect_from_forgery in : null_session sul file application_controller.rb.

Così,

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

1

Se stai usando jQuery con le rotaie, fai attenzione a consentire l'accesso ai metodi senza verificare il token di autenticità.

jquery-ujs può gestire i token per te

Dovresti averlo già come parte della gemma jquery-rails, ma potresti doverlo includere in application.js con

//= require jquery_ujs

Questo è tutto ciò di cui hai bisogno: la tua chiamata ajax ora dovrebbe funzionare

Per ulteriori informazioni, consultare: https://github.com/rails/jquery-ujs



0

Quando si definisce il proprio modulo html, è necessario includere la stringa del token di autenticazione, che deve essere inviata al controller per motivi di sicurezza. Se si utilizza l'helper del modulo rotaie per generare il token di autenticità viene aggiunto al modulo come segue.

<form accept-charset="UTF-8" action="/login/signin" method="post">
  <div style="display:none">
    <input name="utf8" type="hidden" value="&#x2713;" />
    <input name="authenticity_token" type="hidden" value="x37DrAAwyIIb7s+w2+AdoCR8cAJIpQhIetKRrPgG5VA=">
  </div>
    ...
</form>

Quindi la soluzione al problema è quella di aggiungere il campo authenticity_token o utilizzare rotaie dagli helper piuttosto che compromettere la sicurezza ecc.


1
Grazie per la tua risposta, anche se questo non risponde alla domanda originale. La domanda è stata posta sulla risposta alle richieste JSON ma si sta fornendo una soluzione per un modulo HTML da zero. Quando si effettuano richieste JSON (think API) non si sta inviando un modulo HTML e potrebbe non essere possibile accedere facilmente al token di autenticità.
alexcoco,

a meno che il contenuto della richiesta non sia effettivamente JSON, nel qual caso si desidera impostarlo application/json.
alexcoco,

Capisco che la risposta non è esattamente quello che stai cercando. Ma lo scopo di fornire una risposta correlata è aiutare gli utenti a cercare simili "Problemi di autenticità".
amjad,

mi spiace di averlo rimosso per errore - "puoi impostare Content-Type: application / x-www-form-urlencoded con la soluzione sopra".
amjad,

0

Tutti i miei test funzionavano bene. Ma per qualche ragione avevo impostato la mia variabile d'ambiente su non-test:

export RAILS_ENV=something_non_test

Ho dimenticato di annullare l'impostazione di questa variabile a causa della quale ho iniziato a ricevere ActionController::InvalidAuthenticityTokenun'eccezione.

Dopo il disinserimento $RAILS_ENV, i miei test hanno ripreso a funzionare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.