Cómo anular X-Frame-Options para un controlador o acción en Rails 4

88

Rails 4 parece establecer un valor predeterminado SAMEORIGINpara el X-Frame-Optionsencabezado de respuesta HTTP. Esto es excelente para la seguridad, pero no permite que partes de su aplicación estén disponibles en un iframedominio diferente.

Puede anular el valor de X-Frame-Optionsglobalmente usando la config.action_dispatch.default_headersconfiguración:

config.action_dispatch.default_headers['X-Frame-Options'] = "ALLOW-FROM https://apps.facebook.com"

Pero, ¿cómo lo anula para un solo controlador o acción?

Chris Peters
fuente

Respuestas:

137

Si desea eliminar el encabezado por completo, puede crear un after_actionfiltro:

class FilesController < ApplicationController
  after_action :allow_iframe, only: :embed

  def embed
  end

private

  def allow_iframe
    response.headers.except! 'X-Frame-Options'
  end
end

O, por supuesto, puede codificar el after_actionpara establecer el valor en algo diferente:

class FacebookController < ApplicationController
  after_action :allow_facebook_iframe

private

  def allow_facebook_iframe
    response.headers['X-Frame-Options'] = 'ALLOW-FROM https://apps.facebook.com'
  end
end

Tenga en cuenta que debe borrar su caché en ciertos navegadores (Chrome para mí) mientras depura esto.

Chris Peters
fuente
¿Cómo lograría que esto funcione en un redirect_to? (Lo estoy intentando ahora con mi aplicación Angular y no funciona)
kittyminky
Asumiría que tanto la acción que contiene redirect_toy la acción a la que redirige necesitarían aplicar esto. ¿Está recibiendo un error en particular? ¡Suena como una buena pregunta nueva en Stack Overflow!
Chris Peters
Me di cuenta de que tenía el after_action antes de que se redirigiera a la acción final del controlador que redirige a las Angularrutas. ¡Gracias!
kittyminky
No es necesario hacer esto en un after_action, aunque es útil hacerlo, por ejemplo, en un Frontend::BaseControllerdonde se aplica a toda la interfaz. También puedes correr response.headers.except! ...dentro de una acción.
codener
2
A partir de ahora, no funciona en Chrome. El error de la consola es "Se encontró un encabezado 'X-Frame-Options' no válido al cargar 'child': 'ALLOW-FROM parent' no es una directiva reconocida. El encabezado será ignorado". Marcado como no se solucionará en Chromium, con una alternativa: "'frame-ancestors' está disponible tanto en Chrome como en Firefox, y es la forma correcta de admitir esta funcionalidad". bugs.chromium.org/p/chromium/issues/detail?id=129139
richardkmiller
5

Solo quería incluir una respuesta actualizada aquí para cualquiera que encuentre este enlace cuando intente averiguar cómo permitir que su aplicación Rails se incruste en un I-Frame y tenga problemas.

Al momento de escribir esto, el 28 de mayo de 2020, los cambios de X-Frame-Options probablemente no sean la mejor solución a su problema. La opción "PERMITIR DESDE" ha sido totalmente rechazada por los principales navegadores.

La solución moderna es implementar una política de seguridad de contenido y establecer una política de 'frame_ancestors'. La clave 'frame_ancestors' designa qué dominios pueden incrustar su aplicación como un iframe. Actualmente es compatible con los principales navegadores y anula sus X-Frame-Options. Esto le permitirá evitar el secuestro de clics (con el que originalmente se pretendía ayudar X-Frame-Options antes de que se volviera obsoleto) y bloquear su aplicación en un entorno moderno.

Puede configurar una política de seguridad de contenido con Rails 5.2 en un inicializador (ejemplo a continuación), y para Rails <5.2 puede usar una gema como la gema Secure Headers: https://github.com/github/secure_headers

También puede anular las especificaciones de la política en función del controlador / acción si lo desea.

Las políticas de seguridad de contenido son excelentes para las protecciones de seguridad avanzadas. Consulte todas las cosas que puede configurar en los documentos de Rails: https://edgeguides.rubyonrails.org/security.html

Un ejemplo de Rails 5.2 para una política de seguridad de contenido:

# config/initializers/content_security_policy.rb    
    Rails.application.config.content_security_policy do |policy|
      policy.frame_ancestors :self, 'some_website_that_embeds_your_app.com'
    end

Un ejemplo de un cambio específico del controlador en una política:

# Override policy inline
class PostsController < ApplicationController
  content_security_policy do |p|
    p.frame_ancestors :self, 'some_other_website_that_can_embed_posts.com'
  end
end
armont_development
fuente
También puede usar una lambda para valores dinámicos:p.frame_ancestors :self, -> { company&.allowed_domain || 'none' }
Sharagoz
0

Para Rails 5+, use response.set_header('X-Frame-Options', 'ALLOW-FROM https://apps.facebook.com')en su lugar. O si ALLOW-FROMno funciona y necesita una solución rápida, puede configurarlo enALLOWALL

camilo.forero
fuente