🦔

ブラウザの同一オリジンポリシーとCORS:異なるサイト間でのアクセス制限を理解する

に公開

ブラウザの同一オリジンポリシーとCORS:異なるサイト間でのアクセス制限を理解する

はじめに

Webアプリケーション開発において、異なるドメイン間でのデータ通信が必要となり、以下のエラーメッセージに遭遇した。

Refused to connect to 'https://api.example.com/data' because it violates the following Content Security Policy directive: "connect-src 'self'"

これはブラウザに組み込まれたセキュリティ機能であり、その際に調べたことをまとめる。

同一オリジンからのアクセスとクロスオリジンアクセスの違い

ブラウザでhttp://127.0.0.1:8080を開いて開発者ツールのconsoleから実行したところ、エラーは出ないが、googleのトップで開発者ツールを開くと失敗しました。

呼び出し元 結果 エラーメッセージ
http://127.0.0.1:8080/ 成功 なし
https://example.com/ 失敗 Refused to connect... because it violates the following Content Security Policy directive...

調べていくと、ブラウザに実装されている「同一オリジンポリシー(Same-Origin Policy)」というセキュリティ機構によるものらしいです。

同一オリジンポリシーとは

同一オリジンポリシーは、あるオリジン(プロトコル、ドメイン、ポートの組み合わせ)のドキュメントやスクリプトが、別のオリジンのリソースとやり取りすることを制限するセキュリティ機構です。

オリジンの定義:

  • プロトコル(http, https)
  • ドメイン(example.com, localhost)
  • ポート番号(:80, :8080)

例えば、http://example.com:8080https://example.comは、プロトコルが異なるため別のオリジンとみなされます。

セキュリティ上の重要性

この制限が存在する理由は次のような脆弱性が生じる可能性のためなのでした!

  1. クロスサイトリクエストフォージェリ(CSRF):悪意あるサイトが、ユーザーが認証済みの他サイトに対して勝手にリクエストを送信

  2. 情報漏洩:ユーザーがログインしているサービスの情報を、別サイトのスクリプトが読み取る

  3. セッションハイジャック:ユーザーの認証情報を盗み、なりすましを行う

効いてくれていてむしろありがとう・・・

クロスオリジンリソース共有(CORS)による解決

異なるオリジン間での通信を安全に実現するための仕組みとして、「クロスオリジンリソース共有(Cross-Origin Resource Sharing, CORS)」が存在します。

CORSは、サーバー側で特定のオリジンからのアクセスを明示的に許可することで、クロスオリジンのリクエストを可能にする仕組みです。

サーバー側の実装例(Go言語)

func handleRequest(w http.ResponseWriter, r *http.Request) {
    // CORSヘッダーの設定
    w.Header().Set("Access-Control-Allow-Origin", "https://trusted-site.com")
    w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
    w.Header().Set("Access-Control-Allow-Headers", "X-Host, X-Secret-Key, Content-Type")
    
    // プリフライトリクエスト(OPTIONS)への対応
    if r.Method == "OPTIONS" {
        w.WriteHeader(http.StatusOK)
        return
    }
    
    // 通常のリクエスト処理
    // ...
}

解決策

つまり、今回の状況に対する解決策としては、以下がよさそうです。

  1. サーバー側でCORSを適切に設定する

    • 最も直接的な解決策ですが、セキュリティ上の配慮が必要
  2. 同一オリジンからアクセスする

    • フロントエンドとバックエンドを同じオリジンでホスティング
    • これが簡単
  3. プロキシサーバーを導入する

    • フロントエンドと同じオリジンのプロキシを経由してAPIにアクセス
  4. バックエンドによる間接アクセス

    • フロントエンドからバックエンドへリクエストし、バックエンドから対象APIへアクセス

まとめ

ブラウザの同一オリジンポリシーとCORSが理解できた!

Discussion