Rails 4 Autenticidad Token

Estaba trabajando en una nueva aplicación de Rails 4 (en Ruby 2.0.0-p0) cuando me encontré con algunos problemas de token de autenticidad.

Mientras escribía un controlador que responde a json (usando el método de la clase respond_to ), llegué a la acción de create . Empecé a recibir excepciones de ActionController::InvalidAuthenticityToken cuando traté de crear un registro usando curl .

Me aseguré de configurar -H "Content-Type: application/json" y configuré los datos con -d "" pero todavía no -d "" suerte.

Intenté escribir el mismo controlador usando Rails 3.2 (en Ruby 1.9.3) y no obtuve ningún problema de token de autenticidad. Busqué y vi que había algunos cambios con tokens de autenticidad en Rails 4. Por lo que entiendo, ¿ya no se insertan automáticamente en los formularios? Supongo que esto está afectando de alguna manera a los tipos de contenido que no son HTML.

¿Hay alguna forma de evitar esto sin tener que solicitar un formulario HTML, arrebatar el token de autenticidad y luego hacer otra solicitud con ese token? ¿O me estoy perdiendo completamente algo que es completamente obvio?

Editar: Intenté crear un nuevo registro en una nueva aplicación de Rails 4 utilizando un andamio sin cambiar nada y me encuentro con el mismo problema, así que supongo que no es algo que hice.

Creo que lo descubrí. Cambié el (nuevo) valor predeterminado

 protect_from_forgery with: :exception 

a

 protect_from_forgery with: :null_session 

según el comentario en ApplicationController .

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

Puede ver la diferencia mirando la fuente de request_forgery_protecton.rb o, más específicamente, las siguientes líneas:

En 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 

En Rails 4 :

 def handle_unverified_request forgery_protection_strategy.new(self).handle_unverified_request end 

Que llamará a lo siguiente :

 def handle_unverified_request raise ActionController::InvalidAuthenticityToken end 

En lugar de desactivar la protección csrf, es mejor agregar la siguiente línea de código en el formulario

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

y si está utilizando form_for o form_tag para generar el formulario, automáticamente agregará la línea de código anterior en el formulario

Agregar la siguiente línea en el formulario funcionó para mí:

 < %= hidden_field_tag :authenticity_token, form_authenticity_token %> 

No creo que sea bueno desactivar la protección CSRF en general, siempre y cuando no implementes una API exclusivamente.

Cuando miro la documentación de Rails 4 API para ActionController , descubrí que puede desactivar la protección contra falsificaciones por controlador o por base de método.

Por ejemplo, desactivar la protección CSRF para los métodos que puede usar

 class FooController < ApplicationController protect_from_forgery except: :index 

Encontré el mismo problema. Se solucionó al agregar a mi controlador:

  skip_before_filter :verify_authenticity_token, if: :json_request? 

¿Has probado?

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

Este documento oficial habla de cómo desactivar la protección contra falsificaciones para api correctamente http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html

Esta es una característica de seguridad en Rails. Agregue esta línea de código en la forma:

 < %= hidden_field_tag :authenticity_token, form_authenticity_token %> 

La documentación se puede encontrar aquí: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html

Estas características se agregaron con fines de seguridad y protección contra falsificaciones.
Sin embargo, para responder a su pregunta, aquí hay algunas entradas. Puede agregar estas líneas después de su nombre de controlador.

Al igual que,

 class NameController < ApplicationController skip_before_action :verify_authenticity_token 

Aquí hay algunas líneas para diferentes versiones de Rails.

Carriles 3

skip_before_filter: verify_authenticity_token

Rails 4 :

skip_before_action: verify_authenticity_token

Si tiene la intención de deshabilitar esta característica de seguridad para todas las rutinas del controlador, puede cambiar el valor de protect_from_forgery a : null_session en su archivo application_controller.rb.

Al igual que,

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

Si está utilizando jQuery con Rails, tenga cuidado de permitir la entrada a métodos sin verificar el token de autenticidad.

jquery-ujs puede administrar los tokens por ti

Deberías tenerlo ya como parte de la gem jquery-rails, pero es posible que necesites incluirlo en application.js con

 //= require jquery_ujs 

Eso es todo lo que necesita: su llamada ajax ahora debería funcionar

Para obtener más información, consulte: https://github.com/rails/jquery-ujs

Agregar authenticity_token: true a la etiqueta del formulario

Cuando define su propio formulario html, debe incluir la cadena de token de autenticación, que debe enviarse al controlador por razones de seguridad. Si usa rails form helper para generar el token de autenticidad, se agrega al formulario de la siguiente manera.

 
...

Entonces, la solución al problema es agregar el campo authenticity_token o usar rails como helpers en lugar de comprometer la seguridad, etc.

Todas mis pruebas estaban funcionando bien. Pero por alguna razón, establecí mi variable de entorno como no prueba:

 export RAILS_ENV=something_non_test 

Olvidé desactivar esta variable porque empecé a recibir la excepción ActionController::InvalidAuthenticityToken .

Después de desactivar $RAILS_ENV , mis pruebas comenzaron a funcionar nuevamente.