How do you set X-Frame-Options in Phoenix?

I am attempting to iframe a page from a Phoenix app inside a Chrome Extension for a hobby project.

How do I configure the X-Frame-Options? I am not sure the best/safest way to adjust this.

  defp put_secure_defaults(conn) do
    merge_resp_headers(conn, [
      {"x-frame-options", "SAMEORIGIN"},
      {"x-xss-protection", "1; mode=block"},
      {"x-content-type-options", "nosniff"}
    ])
  end

If youā€™re accessing it from ā€œoutsideā€ youā€™ll probably have to unset the header, hereā€™s a Plug for that (you can add it to a relevant Phoenix pipeline):

  defmodule App.Plug.Restrict.AllowIframe do
  @moduledoc """
  Allows affected ressources to be open in iframe.
  """

  alias Plug.Conn

  def init(opts \\ %{}), do: Enum.into(opts, %{})

  def call(conn, _opts) do    
    Conn.delete_resp_header(conn, "x-frame-options")
  end

end

I dinā€™t play with the options that much though, there maybe a way to whitelist your origin which would be a bit safer.

Thanks!

That worked and got me looking in the right direction.

I am experimenting with using Conn.put_resp_header to over write the default value as well.

def call(conn, _opts) do
  Conn.put_resp_header(conn,"x-frame-options","ALLOW-FROM https://example.com")
end
1 Like

I tried something similar first but it didnā€™t work right away so I removed the header (not much of a security issue in our case).

Please let me know if you get a working whitelist.

This works for me:

defmodule App.Restrict.AllowIframe do
  @moduledoc """
  Allows affected ressources to be open in iframe.
  """
  alias Plug.Conn

  def init(opts \\ %{}), do: Enum.into(opts, %{})

  def call(conn, _opts) do
    Conn.put_resp_header(conn,"x-frame-options","ALLOW-FROM https://example.com")
  end

end

ok, now I remember :slight_smile: This worked fine but I wanted more then one exception, tried comma / space separated and then switched to removing the header.

I googled it now and it seems indeed to be a limitation https://stackoverflow.com/questions/10205192/x-frame-options-allow-from-multiple-domains

So itā€™s x-frame-options for one domain or content-security-policy for more.

Iā€™m working on allowing iframe embeds from another site to my phoenix server.

Hereā€™s the trouble Iā€™m running into:

doing Conn.put_resp_header(conn, "content-security-policy", "frame-src" 'self' https://mydomain")
results in the frame not displaying due to an error of ā€˜x-frame-optionsā€™ being set to ā€œSAMEORIGINā€ in chrome.

doing Conn.put_resp_header(conn, "x-frame-options", "ALLOW-FROM https://mydomain")
as suggested above allows the iframe to work. However, I still get an error, even though the frame displays.

Problem: This doesnā€™t seem to be a whitelist, but Iā€™m not certain.
The iframe is properly displaying on my whitelisted domain, on a completely different webservice than my Phoenix server. However, I can use a different computer, not on the white list, to display an iframe containing the site when hosted locally with a simple index.html and <iframe> tag.

The error it displays when running the index.html on my local, non-whitelisted computer is:
Invalid 'X-Frame-Options' header encountered when loading 'http://myPhoenixServer 'ALLOW-FROM https://MyOtherHost' is not a recognized directive. The header will be ignored.
But, it still pulls the webpage from the phoenix host and displays it in the iframe, CSS/JS/HTML and all.

Sorry I am replying to this one year later, just throwing this out there so if someone else finds this thread is does not run into the same thing.

According to the spec the option "allow-from https://example.com/" is not supported in Chrome or Safari, that is probably why you ran into this issue.

3 Likes

it seems that frame-ancestors overrides x-frame-options so all you need to do is something like:

defp framething(conn, _) do
    put_resp_header(conn,"x-frame-ancestors","'self' https://<CHROME ID>.chromiumapp.org") 
end