Rails 4 Token di autenticità

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

Durante la scrittura di un controller che risponde a json (utilizzando il metodo respond_to class), sono arrivato all’azione create che ho iniziato ad ottenere le eccezioni ActionController::InvalidAuthenticityToken quando ho provato a creare un record usando curl .

Mi sono assicurato di impostare -H "Content-Type: application/json" e ho impostato i dati con -d "" ma ancora senza fortuna.

Ho provato a scrivere lo stesso controller usando Rails 3.2 (su Ruby 1.9.3) e non ho avuto problemi di token di autenticità. Ho cercato in giro e ho visto che c’erano alcuni cambiamenti con i token di autenticità in Rails 4. Da quanto ho capito, non sono più automaticamente inseriti nei moduli? Suppongo che questo influenzi in qualche modo i tipi di contenuto non HTML.

C’è un modo per aggirare questo senza dover richiedere un modulo HTML, strappando il token di autenticità, quindi facendo un’altra richiesta con quel token? O mi manca completamente qualcosa che è completamente ovvio?

Edit: ho appena provato a creare un nuovo record in una nuova app di Rails 4 usando uno scaffold senza modificare nulla e mi sto imbattendo nello stesso problema quindi immagino che non sia qualcosa che ho fatto.

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

 protect_from_forgery with: :exception 

a

 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 per request_forgery_protecton.rb , o, più specificamente, le seguenti linee:

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 

Invece di distriggersre 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, allora aggiungerà automaticamente la riga di codice sopra nel modulo

Aggiungere la seguente riga nel modulo ha funzionato per me:

 <%= hidden_field_tag :authenticity_token, form_authenticity_token %> 

Non penso che sia opportuno distriggersre generalmente la protezione CSRF finché non si implementa esclusivamente un’API.

Osservando la documentazione dell’API di Rails 4 per ActionController ho scoperto che è ansible distriggersre la protezione dai falsi su un controller o una base di metodi.

Ad esempio, per distriggersre la protezione CSRF per i metodi che è ansible utilizzare

 class FooController < ApplicationController protect_from_forgery except: :index 

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

  skip_before_filter :verify_authenticity_token, if: :json_request? 

Hai provato?

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

Questo documento ufficiale parla di come distriggersre correttamente la protezione dalla contraffazione per api http://api.rubyonrails.org/classs/ActionController/RequestForgeryProtection.html

Questa è una funzionalità di sicurezza in Rails. Aggiungi questa riga di codice nel modulo:

 <%= hidden_field_tag :authenticity_token, form_authenticity_token %> 

La documentazione può essere trovata qui: http://api.rubyonrails.org/classs/ActionController/RequestForgeryProtection.html

Queste funzionalità sono state aggiunte per scopi di sicurezza e di falsificazione.
Tuttavia, per rispondere alla tua domanda, ecco alcuni input. È ansible 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 rail.

Rails 3

skip_before_filter: verify_authenticity_token

Rotaie 4 :

skip_before_action: verify_authenticity_token

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

Così,

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

Se utilizzi jQuery con le guide, 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 gem jquery-rails, ma potresti aver bisogno di includerlo in application.js con

 //= require jquery_ujs 

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

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

Aggiungi authenticity_token: true al tag form

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

 
...

Quindi, la soluzione al problema è aggiungere il campo authenticity_token o utilizzare i rails help dei form invece di compromettere la sicurezza, ecc.

Tutti i miei test stavano funzionando bene. Ma per qualche motivo ho impostato la variabile di ambiente su non test:

 export RAILS_ENV=something_non_test 

Ho dimenticato di disabilitare questa variabile a causa della quale ho iniziato a ricevere l’eccezione ActionController::InvalidAuthenticityToken .

Dopo aver $RAILS_ENV , i miei test hanno iniziato a funzionare di nuovo.