Como substituir as opções do X-Frame para um controlador ou ação no Rails 4

89

O Rails 4 parece definir um valor padrão de SAMEORIGINpara o X-Frame-Optionscabeçalho de resposta HTTP. Isso é ótimo para segurança, mas não permite que partes do seu aplicativo estejam disponíveis em um iframedomínio diferente.

Você pode substituir o valor de X-Frame-Optionsglobalmente usando a config.action_dispatch.default_headersconfiguração:

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

Mas como você o substitui por apenas um único controlador ou ação?

Chris Peters
fonte

Respostas:

137

Se quiser remover o cabeçalho completamente, você pode criar um 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

Ou, é claro, você pode codificar o after_actionpara definir o valor para 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

Observe que você precisa limpar o cache em certos navegadores (Chrome para mim) durante a depuração.

Chris Peters
fonte
Como você faria isso funcionar em um redirect_to? (Estou tentando agora com meu aplicativo Angular e não está funcionando)
kittyminky
Eu presumiria que tanto a ação que contém o redirect_toquanto a ação para a qual ele redireciona precisariam que isso fosse aplicado. Você está recebendo um erro específico? Parece uma boa pergunta nova no Stack Overflow!
Chris Peters,
Percebi que tinha o after_action antes de ser redirecionado para a ação final do controlador que redireciona para as Angularrotas. Obrigado!
kittyminky
Não é necessário fazer isso em um after_action, embora seja útil fazê-lo, por exemplo, em a Frontend::BaseControlleronde se aplica a todo o frontend. Você também pode correr response.headers.except! ...dentro de uma ação.
codener de
2
A partir de agora, não está funcionando no Chrome. O erro do console é "Cabeçalho 'X-Frame-Options' inválido encontrado ao carregar 'filho': 'ALLOW-FROM pai' não é uma diretiva reconhecida. O cabeçalho será ignorado." Marcado como não corrige no Chromium, com uma alternativa: "'frame-ancestors' está disponível no Chrome e no Firefox e é a maneira certa de oferecer suporte a essa funcionalidade." bugs.chromium.org/p/chromium/issues/detail?id=129139
richardkmiller
8

Eu só queria incluir uma resposta atualizada aqui para qualquer pessoa que encontrar este link ao tentar descobrir como permitir que seu aplicativo Rails seja incorporado em um I-Frame e encontrar problemas.

No momento em que escrevi isso, 28 de maio de 2020, as alterações das Opções do X-Frame provavelmente não são sua melhor solução para o seu problema. A opção "ALLOW-FROM" foi totalmente proibida por todos os principais navegadores.

A solução moderna é implementar uma Política de Segurança de Conteúdo e definir uma política 'frame_ancestors'. A chave 'frame_ancestors' designa quais domínios podem incorporar seu aplicativo como um iframe. Atualmente é compatível com os principais navegadores e substitui as opções do X-Frame. Isso permitirá que você evite o Clickjacking (para o qual o X-Frame-Options foi originalmente criado para ajudar antes de se tornar obsoleto) e bloqueie seu aplicativo em um ambiente moderno.

Você pode configurar uma Content-Security-Policy com Rails 5.2 em um inicializador (exemplo abaixo), e para Rails <5.2 você pode usar uma gem como a gem Secure Headers: https://github.com/github/secure_headers

Você também pode substituir as especificações de política em uma base de controlador / ação, se desejar.

As políticas de segurança de conteúdo são ótimas para proteções de segurança avançadas. Verifique todas as coisas que você pode configurar nos documentos Rails: https://edgeguides.rubyonrails.org/security.html

Um exemplo do Rails 5.2 para uma política de segurança de conteúdo:

# 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

Um exemplo de uma mudança específica do controlador em uma 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
fonte
Também pode usar um lambda para valores dinâmicos:p.frame_ancestors :self, -> { company&.allowed_domain || 'none' }
Sharagoz
Estou usando frame_ancestorse funciona em todos os navegadores, menos no Safari. Alguma ideia?
Matt
@Matt - Acredito que o Safari atualmente impede que iframes de terceiros armazenem cookies - essa é uma das principais limitações do uso de iframes no Safari e pode ser a causa do problema. Pelo que eu sei, não existem boas soluções alternativas. Verifique este estouro de pilha para obter mais informações: stackoverflow.com/questions/59723056/…
armont_development
0

Para Rails 5+, use response.set_header('X-Frame-Options', 'ALLOW-FROM https://apps.facebook.com'). Ou se ALLOW-FROMnão funcionar e você precisar de uma solução rápida, pode configurá-lo paraALLOWALL

camilo.forero
fonte