はじめに
RailsでAPIを作っていますが、CORSの設定を行う必要がありました。そもそもCORSについてわかっていなかったので、CORSについてと、RailsでのCORS設定について説明していきます。
このページで説明すること
- CORSとは
- オリジンとは、同一オリジンとは
- RailsでのCORS設定
- プリフライトリクエストとは
バージョン
- Ruby 2.5.1
- Rails5
- APIモードでプロジェクト作成してます
CORSとは??
Cross Origin Resource Sharing の略。自分以外のどのオリジンからのCRUDリクエストを受け付けるか、受け付けないかをサーバーがフィルターし、セキュリティを高めるためのものです。
もう少し詳しく言うと・・・
Webブラウザは私たちが知らない間に、HTMLや画像、フォントなどを取得するための多くのリクエストをサーバに送信しています。これらのリクエストはインターネットという大海原から大量に送信されてくるため、これらのリクエストが怪しくないか、ハッキングしようとしていないかをチェックせずにリソースを送り返すのはセキュリティ上大きなリスクとなりますよね。
そのため、Webブウラウザから送信されてくるリクエストが正当なものかどうかをチェックするための仕組み(セキュリティーポリシー)が存在しています。「同一生成元ポリシー(Same-Origin Policy)」 です。
「同一生成元ポリシー(Same-Origin Policy)」 を使うことで、異なるオリジンからのリソースへのアクセスに制限をかけることができます。あるページを開いたときに関連するリソースを、同じオリジンからしか取得しない様にするのです。結果的に、クロスサイトリクエストフォージェリ(CSRF) などのセキュリティリスクを防ぐことができます。
CORSはこの制限を一部解除し、異なるオリジン間でリソースを共有できるようにするための仕組みです。
オリジン(Origin)とは?
オリジンとは、URLのスキーム・ホスト・ポートの3つの組み合わせの事をいいます。
http://www.exsample.com:80/index.htmlというURLを例にすると、
- スキーム:
http:// - ホスト:
www.exsample.com - ポート:
80(ポート番号は省略可)
AとBという2つのオリジンがあったとして、**この3つがすべて一致したときのみ「AとBは同じオリジンである」**と言えます。
例えば・・・
オリジンA: http://example.com/app1/index.html
オリジンB: http://example.com/app2/index.html
➡️スキーム (http) とホスト (example.com) が同じなのでAとBは同一オリジンである
オリジンA: http://example.com/app1
オリジンB: https://example.com/app2
➡️スキームが異なるので、同じオリジンではない
オリジンA: http://example.com
オリジンB: http://www.example.com
オリジンC: http://myapp.example.com
➡️ホストが異なるので、同じオリジンではない
同一オリジンである条件
長々と説明しましたが、「同一オリジンである」とは、以下の全てを満たす場合です。
✅ URLのホストが一致している
✅ スキーム(プロトコル)が一致している
✅ ポート番号が一致している
詳しくはMDNの「Origin (オリジン)」を読んでみてください。
Rails APIでのCORS設定
Rails APIは、rack-corsのgemを使って簡単にCORSの設定ができます。
- rack-corsのGithubページは「こちら」
APIモードでRailsアプリを作っている場合、既にGemfileにrack-corsが記載されていますが、デフォルトだとコメントアウトされています。コメントアウトを解除してbundle installします。
gem 'rack-cors'
bundle installするとconfig/initializers/cors.rbが自動生成されるので、そのファイルを編集していきます。
基本設定
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
特定のオリジンのみ許可する
origins "*"は、どのオリジンからのリクエストも受け付ける設定です。特定のオリジンからのリクエストを許可したい場合は、下記の様に変更します。
localhost:3000とhttps://www.sample.comからのリクエストを許可したい場合
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'localhost:3000','https://www.sample.com'
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
Cookieを利用する
Cookieを利用する場合はcredentials: trueを追記します。
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'localhost:3000'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head],
credentials: true
end
end
Methods内の :options は何??
methods内に記載されている:optionsはプリフライトリクエストのために必要なので、消さない様にしましょう。
プリフライトリクエストって?
CORSを用いると、異なるオリジンにPUT等のCRUDリクエストを送る際、そのリクエストが許可されていることをサーバに一度確認してからでないと、リクエストを送ることができなくなります。このリクエストのことを、プリフライトリクエストと言います。
このリクエストのメソッドにOPTIONSが使用されます。そのため、OPTIONSリクエストとも呼ばれます。
例えば、update(PUT/PATCH)リクエストでデータベース内のレコードをアップデートするとします。PUT/PATCHリクエストが送信される前に、まずプリフライトリクエストがサーバに送信され、送信元オリジンからのPUT/PATCHリクエストが有効かどうかをチェックします。
有効でない場合はconsoleにResponse to preflight request doesn't pass access control check:といったエラーメッセージが表示され、WebブラウザはCRUDリクエストの送信を断念します。
CORSを有効にするとこのプリフライトリクエストのために、Optionsメソッドが必要なので、methods内の:optionsを削除すると動かなくなります。注意しましょう。
まとめ
以上、CORSの解説とRuby on Railsでの設定方法のご紹介でした。
宣伝: Railsアプリの作り方を学べる教材を公開しています!
Techpit様にて、Ruby on RailsとVue.jsでリアルタイムチャットアプリを作る教材を公開しています。
本記事で紹介したCORS設定はもちろんのこと、HTTP通信やAction Cableを使用したWebsocket通信についても詳しく説明しています。Rails APIモードでアプリケーションを作って見たい方はぜひ購入してください!