es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Rails API + React Frontend: ¿cómo hacer que la cookie CSRF NO sea httponly?

Tengo una API de Rails 6 y un frontend de React y me gustaría mantener verify_authenticity_token en todas las acciones del controlador.

El backend establece el token CSRF de la siguiente manera en application_controller.rb:

class ApplicationController < ActionController::Base
  ...

  include ActionController::Cookies
  after_action :set_csrf_cookie

  ...

  protected

  def verified_request?
    super || request.headers['X-CSRF-Token'] === cookies['X-CSRF-Token']
  end

  def set_csrf_cookie
    if protect_against_forgery? && current_user
      cookies['X-CSRF-Token'] = {
        value: form_authenticity_token,
        httponly: false
      }
    end
  end

end

El frontend intenta usar js-cookie para obtener las cookies. Tengo lo siguiente en un archivo cookies.js:

import Cookies from 'js-cookie'

const getCSRFToken = () => {
  window.Cookies = Cookies;
  const token = Cookies.get('X-CSRF-Token')

  return token
}

export default getCSRFToken

Y llamo a esta función cuando creo una solicitud Axios. La función para construir la solicitud toma parámetros como método, URL, datos, etc.:

export const newAxiosIns = params => {
  // Los parámetros serán un hash de distintos encabezados
  const defaultParams = {
    baseURL: baseUrl,
    withCredentials: true,
    headers: {
      common: {
        'X-CSRF-TOKEN': getCSRFToken()
      }
    }
  }

  const axiosIns = axios.create(defaultParams)

  return axiosIns(params)
}

Pero las cookies terminan siendo httponly en Chrome:
captura de pantalla que muestra httponly marcado

Me pregunté si tenía que ver con el form_authenticity_token, así que hice un token falso con un valor de ‘faker’, pero tampoco era httponly.

¡Gracias!

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Solución

    El problema parece ser que la bandera httponly está establecida en true cuando se establece el token CSRF en el método set_csrf_cookie en el ApplicationController. Esto significa que la cookie no se puede acceder desde JavaScript, por lo que la biblioteca js-cookie no puede recuperarla.

    Para solucionar este problema, puedes establecer la bandera httponly en false al configurar la cookie del token CSRF en el ApplicationController:

    def set_csrf_cookie
      if protect_against_forgery? && current_user
        cookies['X-CSRF-Token'] = {
          value: form_authenticity_token,
          httponly: false # <-- establecer httponly en false
        }
      end
    end
    

    Esto permitirá que el frontend recupere la cookie del token CSRF utilizando la biblioteca js-cookie.

    Además, ten en cuenta que el nombre del encabezado que se utiliza para enviar el token CSRF en el frontend (X-CSRF-TOKEN) es diferente del nombre del encabezado que se lee en el método verified_request? en el backend (X-CSRF-Token). Asegúrate de utilizar el mismo nombre de encabezado en ambos lugares.

    Entonces, la función newAxiosIns debería verse así en cambio:

    export const newAxiosIns = params => {
      const defaultParams = {
        baseURL: baseUrl,
        withCredentials: true,
        headers: {
          common: {
            'X-CSRF-Token': getCSRFToken() // <-- utilizar el mismo nombre de encabezado que en el backend
          }
        }
      }
    
      const axiosIns = axios.create(defaultParams)
    
      return axiosIns(params)
    }
    

    Con estos cambios, la cookie del token CSRF ahora debería poder ser recuperada por el frontend.

Comments are closed.