35

I am using Sinatra to return some IFRAME contents, and I'd like to allow cross-domain src. Unfortunately, Sinatra is automatically adding an X-Frame-Options header to my response. How do I turn that off?

Bruce
  • 8,202
  • 6
  • 37
  • 49

6 Answers6

80

Sinatra uses Rack::Protection, in particular the frame_options option, which is what is setting the X-Frame-Options header.

You can configure which protections are used. Sinatra turns most of them on by default, (some are only enabled if you also are using sessions, and Rack::Protection itself doesn't enable some by default).

To prevent sending the X-Frame-Options header you need to disable frame_options like this:

set :protection, :except => :frame_options
matt
  • 78,533
  • 8
  • 163
  • 197
  • That did the job, thanks! In my scouring of the internet, I'd run across all the individual pieces you mentioned, but hadn't been able to combine them into that one effective line of code that you gave me. Much appreciated. – Bruce Oct 20 '11 at 20:37
  • Thanks a lot, @matt! I'm developing my first app in Sinatra, a Facebook canvas app, and this issue was consuming me for 2 days... :) – rapcal Apr 25 '12 at 04:11
  • **This is a security risk** If you only want to whitelist facebook, and not disable this important security feature at all, better do this: `set :protection, :origin_whitelist => ['https://s-static.ak.facebook.com']` – FeeJai Nov 23 '14 at 00:51
  • 1
    @FeeJai that wouldn’t work (`:origin_whitelist` doesn’t effect `frame_options`). You could do something like `:frame_options => "ALLOW-FROM https://s-static.ak.facebook.com"`, but the `ALLOW-FROM` value isn’t supported on Chrome or Safari. Longer term it may probably be better to use [CSP](https://developer.mozilla.org/en-US/docs/Web/Security/CSP). It looks like [Rack-Protection will be getting support for CSP headers soonish](https://github.com/rkh/rack-protection/pull/75). – matt Nov 23 '14 at 01:48
5

Another solution, and the one I ended up with in production, involves monkey-patching Rack::Protection::FrameOptions:

# This monkeypatch is needed to ensure the X-Frame-Options header is
# never set by rack-protection.
module Rack
  module Protection
    class FrameOptions < Base
      def call(env)
        status, headers, body = @app.call(env)
        [status, headers, body]
      end
    end
  end
end
xentek
  • 2,555
  • 2
  • 20
  • 12
  • I don't get why this is the only solution that worked, but it is! – Spencer Alger Oct 20 '14 at 06:54
  • I can't believe that you do actually use this in production. I believe that this acutally kills *all* security headers. You should provide an exception for the urls that you need instead – FeeJai Nov 23 '14 at 00:49
  • In my case the whole app ran inside facebook's iframe, so it was appropriate. Also, the level of security this header provides is pretty minimal and wholly dependent on client support. – xentek Jan 21 '15 at 07:18
  • @FeeJai the X-Frame headers could hardly be called security and in my testing at the time they were not supported very well by browsers when you were whitelisting URLs. It only seemed to work when they were either on (protect from all frames) or not present, as my solution above illustrates. – xentek Mar 20 '15 at 19:38
3

Neither of the options presented here worked for my sinatra app. I ended up adding an after filter to modify the X-Frame-Options header to allow the app to be framed in by Facebook.

after do
  headers({ 'X-Frame-Options' => 'ALLOW-FROM apps.facebook.com' })
end
xentek
  • 2,555
  • 2
  • 20
  • 12
  • I prefer this solution because: a) it works in sinatra 1.4.3 and b) it is more secure, I can put this statement directly within each individual action so that I can protect all but those I expect from all but those domains I expect. – Saboosh Sep 28 '13 at 02:32
  • 2
    This ended up not working in every browser, so YMMV. – xentek Oct 07 '13 at 19:16
  • As noted above, this is obsolete and should not be used anymore: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options – Blake Gearin Apr 04 '22 at 02:30
3

I think I found a good way to handle this but would welcome feedback

The goal is to disable the X-Frame-Options just for one route to keep all the rack protection benefits:

    app.get'/hello_world' do
      headers({ 'X-Frame-Options' => '' })
      "HELLO WORLD"
    end

I believe this is a good option as it seems to prevent the rack protection from adding the SAMEORIGIN header on this one route

stujo
  • 2,089
  • 24
  • 29
2

The "set :protection, :except => :frame_options" answer did not work for me, using Sinatra-1.3.3

I had to hack a solution; I put this mutha in my config.ru file. Obvs you can change the header to be anything you want.

config.ru

class Rack::Protection::FrameOptions
  def header
    @header ||= {}
  end
end
ted price
  • 21
  • 1
1

Actually, the solution given by @matt is still working with Sinatra v1.4.5.

Yes, Sinatra is using Rack::Protection and according to Configuring attack protection

you could either disable protection at all (which is not recommended):

disable :protection

or only disable frame_options:

set :protection, :except => :frame_options

Other than that, if your problem is not because of X-Frame-Options, it may be Access-Control-Allow-Origin, then what you have to do is to add below line to your route before the return statement:

response['Access-Control-Allow-Origin'] = 'http://www.example.com/'
Jing Li
  • 14,547
  • 7
  • 57
  • 69