クロスオリジン リソース シェアリング(CORS)

同一生成元ポリシーは、生成元が異なるリソース間でやり取りが行われないようにクライアント側のウェブアプリ(ウェブブラウザなど)に適用されるセキュリティ ポリシーです。不正行為の防止には役立ちますが、このセキュリティを適用すると既知の生成元の間での有効で正当なやり取りも行えなくなります。たとえば、example.appspot.com の Google App Engine からホストされているページのスクリプトで、example.storage.googleapis.com の Cloud Storage バケットに保存されている静的なリソースを使用する必要があるとします。ただし、ブラウザから見ると 2 つの異なる生成元があるため、ブラウザは example.appspot.com からのスクリプトが XMLHttpRequest を使用して example.storage.googleapis.com からリソースを取得することを許可しません。これは、取得するリソースの生成元が異なるためです。

この制限の回避策としてクロスオリジン リソース シェアリング(CORS)仕様が World Wide Web Consortium(W3C)で開発されました。Cloud Storage では、CORS 準拠のレスポンスを返すようにバケットを設定することを許可してこの仕様をサポートしています。上記の例を続けると、Cloud Storage は CORS をサポートしているので、ブラウザは、リソースを example.appspot.com のスクリプトと共有する許可を example.storage.googleapis.com に求めることができます。

CORS のしくみ

クライアント側で、ウェブ クライアント(ブラウザ)が Cloud Storage へのリクエストを作成すると、リソースの生成元を含む Origin ヘッダーが自動的に追加され、クロスドメインのリソース(たとえば、Origin:http://www.example.appspot.com)を共有することが求められます。Cloud Storage は独自の CORS 設定でリクエスト ヘッダーにある生成元を調べ、受信した生成元が許可されているかどうか、受信したリクエスト メソッドがその生成元に対して許可されているかどうかを判断します。生成元とメソッドが許可されていると、Cloud Storage はレスポンスにヘッダー Access-Control-Allow-Origin を含めます。クライアント(たとえば、ブラウザ)はこのレスポンス ヘッダーを調べて、レスポンス内のドメインが元のリクエストで指定されているドメインと一致しているかどうかを確認し、一致していれば、リクエストの処理を進めます。一致していない場合や、Access-Control-Allow-Origin ヘッダーがレスポンスにない場合、リクエストは許可されません。

クライアントで CORS をサポートする

ほとんどのクライアント(ブラウザなど)は XMLHttpRequest オブジェクトを使用してクロスドメイン リクエストを作成します。XMLHttpRequest が、適切なヘッダーの挿入やサーバーとの CORS のやり取りの処理の作業をすべて担当します。つまり、CORS のサポートを利用するための新しいコードをユーザーが追加するのではなく、Cloud Storage のバケットが CORS 対応に設定されていると見なされて単に自動的に処理されます。

バケットの CORS を設定する

Cloud Storage では、CORS はバケットレベルでのみ設定できます。クロスドメイン リソースの共有にバケットを使用できるようにするには、バケットを共有するすべての生成元と、そのバケットに対して許可するリクエスト メソッドが含まれているバケットの CORS を設定します。

バケットの CORS を設定する方法は複数あります。

  • gsutil ツールの使用。たとえば、gsutil cors set コマンドを使用して CORS の設定や変更を行うことができます(必要に応じて、gsutil cors get を使用してバケットの CORS 設定を一覧表示します)。
  • XML API または JSON API に直接リクエストを送信。たとえば、XML API の PUT Bucket メソッドを使用し、?cors クエリ パラメータを指定して CORS 設定を変更することができます(必要に応じて、GET Bucket を使用し、?cors クエリ パラメータを指定してバケットの CORS 設定を一覧表示します)。
  • Google Cloud Storage のクライアント ライブラリのいずれかを使用。

CORS の設定にいずれの方法を使用する場合でも、バケットへのアクセスが許可されたすべての生成元とリクエスト メソッドを指定する CORS 設定データをリクエストに含める必要があります。たとえば、example.appspot.com のスクリプトが example.storage.googleapis.com のバケットに保存されている静的なリソースを使用することを許可するには、次の gsutil コマンドまたは XML API リクエストを使用できます。

gsutil

gsutil cors set cors-json-file.json gs://example

ここで、cors-json-file.json には以下が含まれます。

[
    {
      "origin": ["http://example.appspot.com"],
      "responseHeader": ["Content-Type"],
      "method": ["GET", "HEAD", "DELETE"],
      "maxAgeSeconds": 3600
    }
]

XML API

PUT http://storage.googleapis.com/example?cors HTTP/1.1
Host: storage.googleapis.com
Content-Length: 412
Authorization: Bearer ya29.AHES6ZRVmB7fkLtd1XTmq6mo0S1wqZZi3-Lh_s-6Uw7p8vtgSwg

<?xml version="1.0" encoding="UTF-8"?>
<CorsConfig>
  <Cors>
    <Origins>
      <Origin>http://example.appspot.com</Origin>
    </Origins>
    <Methods>
      <Method>GET</Method>
      <Method>HEAD</Method>
      <Method>DELETE</Method>
    </Methods>
    <ResponseHeaders>
      <ResponseHeader>Content-Type</ResponseHeader>
    </ResponseHeaders>
    <MaxAgeSec>3600</MaxAgeSec>
  </Cors>
</CorsConfig>

CORS 設定の JSON ファイルのフィールドについて詳しくは、JSON API の Buckets リソースの説明をご覧ください。

CORS 設定の XML のフィールドについて詳しくは、PUT Bucket メソッドの説明をご覧ください。

Cloud Storage へのクロスドメイン リクエストの送信

許可された任意の XML API リクエスト形式(ブラウザ ダウンロードを除く)を使用して、CORS ヘッダーを含むレスポンスを Cloud Storage から取得することができます。XML API リクエスト形式の詳細については、リクエストの URI をご覧ください。

トップへ戻る

CORS を使用してバケットにアクセスしているときに予期しない振る舞いが発生した場合は、次の手順を試してください。

  1. 問題のあるバケットに対し gsutil cors get を使用して、バケットの CORS 設定が期待どおりであることを確認します。
  2. 希望するツールを使用して、完全なリクエスト/レスポンスを取得します。Chrome ブラウザでは、標準のデベロッパー ツールを使用してこれを確認できます。
    1. ブラウザのツールバーで Chrome メニュー Chrome メニュー アイコン。 をクリックします。
    2. [その他のツール] > [デベロッパー ツール] を選択します。
    3. [Network] タブをクリックします。
    4. ブラウザ リクエストを送信し、ネットワーク アクティビティが表示されているペインで、対象となるリクエストを探します。
    5. [Name] 列で、リクエストに対応する名前をクリックします。
    6. [Headers] タブをクリックしてレスポンス ヘッダーを確認するか、[Response] タブをクリックしてレスポンスの内容を表示します。
  3. リクエストに実際に Origin ヘッダーがあることを確認します。
  4. 送信する Origin ヘッダーが手順 1 で取得した CORS 設定内の少なくとも 1 つの Origins と一致していることを確認します。スキーム、ホスト、ポートがすべて一致している必要があります。たとえば、http://origin.example.com は、https://origin.example.com と一致しておらず、http://origin.example.com:80 または http://origin.example.com:5151 とも一致していません。
  5. 送信する HTTP メソッド(またはプリフライト リクエストの場合は Access-Control-Request-Method で指定されたメソッド)が CORS 設定内の Methods のいずれかと一致していると同時に、Origin とも一致していることを確認します。適用するには、OriginMethod の両方で CORS 設定のエントリが一致している必要があります。CORS 設定のエントリが 2 つあり、一方のエントリでは Origin は一致するが Method が一致せず、もう一方のエントリでは Method は一致するが Origin が一致しない場合は、どちらのエントリも使用されず、レスポンスに CORS ヘッダーは含まれません。
  6. プリフライト リクエストの場合は、プリプライト リクエストに Access-Control-Request-Header が 1 つ以上含まれているかどうかを確認します。組み込まれている場合は、一致する CORS 設定のエントリに、各リクエスト ヘッダーの <ResponseHeader> エントリが含まれていることを確認します。プリフライト リクエストが正常に終了し、レスポンスに CORS ヘッダーが含まれるためには、Access-Control-Request-Header に指定されたすべてのヘッダーが CORS 設定に含まれていることが必要です。
  7. 問題を再現しようとしたときにリクエスト/レスポンスが表示されない場合は、ブラウザのキャッシュに以前失敗したプリフライト リクエストが入っている可能性があります。ブラウザのキャッシュをクリアすると、プリフライトのキャッシュもクリアされる可能性があります。

    <MaxAgeSec> のデフォルト設定は 1,800 秒(30 分)です。ブラウザのキャッシュを通常どおりクリアしても CORS プリフライトのキャッシュがクリアされないと思われる場合は、CORS 設定で <MaxAgeSec> の値を低くし、30 分待ってから再試行してください。これで、新しいプリフライト リクエストが実行され、新しい CORS 設定が取得されます。また、<MaxAgeSec> も選択した新しい低い値に設定されるので、キャッシュ エントリを消去する回数を増加できます。問題をデバッグし終えたら、<MaxAgeSec> を高い値に戻して、バケットへのプリフライトのトラフィックを削減してください。

  8. 再開可能なアップロード プロトコルを使用する場合、最初のリクエスト(アップロードの開始)の Origin が常にレスポンスの Access-Control-Allow-Origin ヘッダーの判定に使用されます。これは、後続のリクエストで異なる Origin を使用している場合でも変わりません。そのため、最初のリクエストと後続のリクエストで同じ Origin を使用するか、最初のリクエストと後続のリクエストで Origin が異なる場合は CORS 設定を <Origin>*</Origin> に指定して XML API を使用する必要があります。

トップへ戻る

フィードバックを送信...

Cloud Storage ドキュメント