Help us understand the problem. What is going on with this article?

CORSがよくわからないので解説してみた&Rails APIでのCORS設定

はじめに

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.sample.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
➡️ホストが異なるので、同じオリジンではない

詳しくはMDNの「Origin (オリジン)」を読んでみてください。

Rails APIでのCORS設定

Rails APIは、rack-corsのgemを使って簡単にCORSの設定ができます。

  • rack-corsのGithubページは「こちら

APIモードでRailsアプリを作っている場合、既にGemfileにrack-corsが記載されていますが、デフォルトだとコメントアウトされています。コメントアウトを解除してbundle installします。

Gemfile
gem 'rack-cors'

bundle installするとconfig/initializers/cors.rbが自動生成されるので、そのファイルを編集していきます。

基本設定

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:3000https://www.sample.comからのリクエストを許可したい場合

config/initializers/cors.rb
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を利用する場合はcredentiials: trueを追記します。

config/initializers/cors.rb
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での設定方法のご紹介でした。

参考サイト

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away