如何在 Rails 4中覆盖控制器或操作的 X-Frame-Options

Rails 4似乎为 X-Frame-Options HTTP 响应头设置了一个默认值 SAMEORIGIN。这是 很好的安全,但它不允许您的应用程序的一部分可用于 iframe在不同的域。

您可以使用 config.action_dispatch.default_headers设置覆盖 X-Frame-Options的全局值:

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

但是如何仅为单个控制器或操作重写它呢?

45243 次浏览

If you want to remove the header completely, you can create an after_action filter:

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


def embed
end


private


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

Or, of course, you can code the after_action to set the value to something different:

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

Note that you need to clear your cache in certain browsers (Chrome for me) while debugging this.

I just wanted to include an updated answer here for anyone who finds this link when trying to figure out how to allow your Rails app to be embedded in an I-Frame and running into issues.

As of writing this, May 28th 2020, the X-Frame-Options changes are probably not your best solution to your problem. The "ALLOW-FROM" option has been totally disallowed by all major browsers.

The modern solution is to implement a Content-Security-Policy and set a 'frame_ancestors' policy. The 'frame_ancestors' key designates what domains can embed your app as an iframe. Its currently supported by major browsers and overrides your X-Frame-Options. This will allow you to prevent Clickjacking (which the X-Frame-Options was originally intended to help with before it largely became deprecated) and lock down your app in a modern environment.

You can set up a Content-Security-Policy with Rails 5.2 in an initializer (example below), and for Rails < 5.2 you can use a gem like the Secure Headers gem: https://github.com/github/secure_headers

You can also override the policy specifications on a controller/action basis if you'd like.

Content-Security-Policies are great for advanced security protections. Check out all the things you can configure in the Rails docs: https://edgeguides.rubyonrails.org/security.html

A Rails 5.2 example for a Content-Security-Policy:

# 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

An example of a controller specific change to a policy:

# 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

For Rails 5+, use response.set_header('X-Frame-Options', 'ALLOW-FROM https://apps.facebook.com') instead. Or if ALLOW-FROM doesn't work and you need a quick fix, you can set it to ALLOWALL

The answers above really helped me, but in 2021 using a Rails 4.2 app I needed to turn off X-Frame-Options and specify a Content-Security-Policy for only a couple URLs.

Specifically I am using 2checkout as a payment provider and they open up some URLs in iframes....

This is how I did it

class HomeController < ApplicationController
after_action :allow_2checkout_iframe, only: [:privacy, :terms_of_service]


def privacy
end


def terms_of_service
end


private
def allow_2checkout_iframe
response.headers.except! 'X-Frame-Options'
response.headers['Content-Security-Policy'] = "frame-ancestors 'self' https://secure.2checkout.com"
end
end