RailsのCORS(オリジン間リソース共有)で特定のドメインからのiFrameのみ許可したい
モチベーション
自分のブログ上に、ブログのドメインと異なるサイトへリリースしたサービスを埋め込みたい。
例えばtoritakashi.comにexample.herokuapp.comのサイト(example.herokuapp.comへのリリース権限あり)を埋め込みたいケース。
ドメインを見るとわかりますが、このWebサービスはHeroku上にリリースしてあります。
直面した問題
オリジン間リソース共有が許可されておらず、iFrameで埋め込むことができない。
Refused to display 'http://example.herokuapp.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
のようにX-Frame-Optionsでsame originが設定されていて読み込めないことがわかります。
example.herokuapp.comにおいてtoritakashi.comによるリソース共有を、読み込み元(Origin)のドメインが異なるという理由で許可していないということです。
解決策
Access-Control-Allow-Origin: *であらゆるオリジンからリソースへアクセスすることを許可します。
そしてヘッダーのX-Frame-Optionsにallow-from uriを、Content-Security-Policyにframe-ancestors uriを設定します。
X-Frame-Optionsのallow-from uriは廃止されたディレクティブですが、ブラウザの後方互換のために書いておきます。
最新のブラウザはContent-Security-Policyのframe-ancestorsを参照し表示許可の判定をしています。
① rack-corsをインストール
Gemfileに
gem 'rack-cors'
を追加し
bundle install
②Access-Control-Allow-Originを設定
config/initializersに
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins '*' resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end
を追加する。
③X-Frame-OptionsとCSPをいじる
許可したいアクションの記述されたコントローラファイルを開き、response.headersを書き換える処理を追加します。
Webサービス全体に対して設定したいときはApplicationControllerに書くなり(未検証)してください。
class HogeHogeController < ApplicationController after_action :allow_iframe, only: [:index] def index end private def allow_iframe url="http://example.herokuapp.com" response.headers['X-Frame-Options'] = "ALLOW-FROM #{url}" response.headers['Content-Security-Policy'] = "frame-ancestors #{url}" end end
解決
リリースブランチにPushして…
無事表示されるようになりました。
めでたしめでたし。