Gem
rack-cors
CORS とは
- リソース共有のための仕組み。
- CORSを指定したからと言ってセキュリティ対策になるわけではなく、むしろ逆。ドメインを共有できるようになるので、セキュリティリスクは増す。
- CORSを許可する場合は、許可する ORIGINとしてワイルドカードを指定せず、可能であればホワイトリストを指定する。
- セキュリティ的なデフォルト挙動が「同一オリジンポリシー」に準拠したものであり、CORSがその間口を広げる。
設定
- Rails構成のAPIサーバーを想定
- localhost:3000 で API サーバーがつながるものとする
- application.rbに以下を設定してサーバーを再起動する
module App
class Application < Rails::Application
# Rails 5
config.middleware.insert_before 0, Rack::Cors do
allow do
# いろいろな形式で、複数指定できる
origins 'example.com', 'https://yahoo.com', 'localhost:9999'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
end
curl での動作確認
- リクエストヘッダの Origin として Rails で 許可した ORIGIN を指定してリクエストする
- 実際のリクエスト元は 自分が利用しているシェルであり、 http://example.com ではないわけだが、ヘッダに指定することは可能だ。
curl --dump-header - "http://localhost:3000/v1/foo" -H "Origin: http://example.com" -H "Content-Type: application/json" HTTP/1.1 200 OK
結果の例
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
...
- プロトコルを問わずにORIGINが許可されているようだ。
- https や ftp のURLを ORIGIN に指定しても Access-Control-Allow-Origin が返ってくる。
curl --dump-header - "http://localhost:3000/v1/foo" -H "Origin: https://example.com" -H "Content-Type: application/json" HTTP/1.1 200 OK
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
注意
-
Origin: http://example.com/
のように末尾にスラッシュをつけると Access-Control-Allow-Origin が返ってこない。 - たとえば Railsの設定で https だけを許可した場合、 リクエストで Origin に http を申告しても、Access-Control-Allow-Origin は返ってこない。
リクエストヘッダの Orign とは何なのか
- あくまでもクライアントの自己申告のようだ。実際のリクエスト送信元がなんであれ、自由に指定できる。別にリクエスト元のIPなどから生成されているわけではない。
- 仕様はクライアントによるはずだ。たとえばブラウザからのリクエスト送信であれば「Originを超えた、自分以外の場所にリクエストをする場合に、自動的に Origin ヘッダに、送信元の正しい Origin を付与する」というような仕様だと思うのだけれど。
- シェルの場合はクライアントとしての仕様があるわけではないので Origin の指定も自由だ。なので、リクエストヘッダとして Origin の指定しなければ、そもそも Origin のヘッダは送信されないみたいだ。たとえそれが Origin を超えたリクエストだろうと、なんだろうと。
- ヘッダを詐称するクライアントの攻撃は防ぐことはできないはずだ。
そんな自己申告の仕組みが脆弱性、セキュリティ対策とどう関係するのだろうか?
- CORSで外部リクエストを許可していた場合、第三者が踏み台のサイトを用意して、善意のユーザーがサーバーにリクエストするような処理を作っていた時に、脆弱性が生まれる場合がある。(クロスサイト系の攻撃って、そういうものですよね) (直接攻撃じゃなくて)
- ユーザーのクライアントであるブラウザは、悪意のある第三者のサイトから、サーバーにリクエストする場合でも、詐称しない、正しいOriginヘッダを投げる。この時にフロント側の制御として、悪意のある送信がおこなわれないようにブロックするということだろうか。
Rspec でリクエストのテストを書く
こんな感じで出来るはず
require "rails_helper"
RSpec.describe type: :request do
subject do
get "/v1/foo", headers: { Origin: "http://example.com" }
end
it do
subject
expect(response.header["Access-Control-Allow-Origin"]).to eq "http://example.com"
end
end
参考
CORS (Cross-Origin Resource Sharing) ってなに?
Original by Github issue
チャットメンバー募集
何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。