share facebook facebook twitter menu hatena pocket slack

2012.09.05 WED

S3ってなんじゃ?(CORS対応)

三浦 悟

WRITTEN BY 三浦 悟

S3がCORS対応になったので、少し触れてみたいと思います。

CORSはCrossDomainResourceSharingの略になります。
JSONP等の特殊なケースを除いて、通常Ajax等ではクロスドメイン通信は認められていませんがCORSは、通信先のサーバーで条件付きで許可をすることでクロスドメインアクセスを可能にするための仕組みで、W3Cで策定されいてる仕様です。
モダンブラウザでは、ほぼサポートされているかと思います。

CORSではブラウザがクロスドメインのサーバーにリクエストする際に、事前にそのサーバーがこれから行おうとしているリクエストを許可しているかどうかをHTTPメソッドの1つであるOPTIONSメソッドといくつかのHTTPリクエストヘッダを用いて問い合わせます。
(Preflightリクエスト)
そして、このレスポンスによりブラウザは通信可能かどうかを判断します。

Preflightリクエストで使用されるヘッダは下記等になります。

  • Origin
    • リクエスト元のオリジン
    • (http://www.example.com/foo/barからリクエストされる場合、http://www.example.com/)
  • Access-Control-Request-Method
    • これからリクエストするときに使用するHTTPメソッド
  • Access-Control-Request-Headers
    • これからリクエストするときに使用するHTTPヘッダー

これらは通常ブラウザが自動で判別してリクエストヘッダに付与します。
それに対してレスポンスヘッダには以下の内容がセットされます。

  • Access-Control-Allow-Origin
    • この項目で指定されたOriginにリクエストが許可されます。
  • Access-Control-Allow-Credentials
    • trueならCookieなどユーザーの資格情報をレスポンスに含めることを許可します
  • Access-Control-Expose-Headers
    • CORS API仕様として公開して良いヘッダーフィールド
  • Access-Control-Max-Age
    • このPreflightリクエストの結果のキャッシュ保持秒数
  • Access-Control-Allow-Methods
    • 許可するHTTPメソッドが含まれます
  • Access-Control-Allow-Headers
    • 許可するリクエストヘッダーが含まれます

ブラウザはこのレスポンスヘッダを見てリクエスト可能かどうかを判断します。
通常は、REST API等を実装しWEBサービスを行うサーバーでは、このCORSに対応するような実装をすることで許可した相手にのみAPIを利用できるように実装を行う必要がありますが、この度S3ではそれが簡単な設定を行うだけで利用できるようになりました。

実際にS3のCORS機能を使って具体的にどんなことが行われているのかを確認してみます。

はじめに、S3にバケットを作り、例として以下のJSONファイルをアップロードします。

{
   "id": "1405028029",
   "name": "Satoru Miura",
   "first_name": "Satoru",
   "last_name": "Miura",
   "link": "https://www.facebook.com/memocra",
   "username": "memocra",
   "gender": "male",
   "locale": "ja_JP"
}

そして、EC2等で立ち上げた別のホストにこのJSONファイルをAjaxで読み込む以下のようなHTMLを配置します。

Graph

WEBブラウザのアドレスバーに直接下記を入力するとロードできますが、別ホストで上記のようなHTMLページからのAjaxではドメインが異なるためロードに失敗します。

http://s3-ap-northeast-1.amazonaws.com/memorycraft/memocra.json

これはchromeブラウザですが、通信内容を確認するとOPTIONSメソッドで送信しており、以下のヘッダを送信していることがわかります。

  • Access-Control-Request-Headers
    • origin, content-type, accept
  • Access-Control-Request-Method
    • GET
  • Host
    • s3-ap-northeast-1.amazonaws.com
  • Origin
    • http://176.34.47.135

これがPreflightリクエストです。
この後Origin、Content-Type、AcceptヘッダをGETメソッドで送るとの連絡をしています。
こちらの結果は403で返ってきました。

バケットのプロパティを確認するとPermissionsタブに、「Edit CORS Configuration」というボタンがあるので
クリックすると以下のようなXMLの設定が表示されます。




*
GET
3000
Authorization

CORSRuleにある設定がこのS3バケットで受け付けている設定になります。
これらは前述(下記)のレスポンスヘッダに該当し、許可する条件を示しています。

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Max-Age
  • Access-Control-Allow-Headers

このデフォルト設定をみると、アクセス元は任意でよく、許可するHTTPでメソッドはGETのみ、認証キャッシュは3000秒で、Authorizationヘッダーのみを許可しています。

Authorizationヘッダーのみの許可なので、本リクエストで送る予定のAccept, Content-Type, Originヘッダーが
許可されず403エラーとなっているようです。
ここで、AllowdHeaderを増やしてみます。




*
GET
3000
Authorization
Accept
Content-Type
Origin

もしくはすべてのヘッダーを受け付けるようにワイルドカード*を指定します。




*
GET
3000
*

そうすると、GETであればアクセス可能になるので、Ajaxリクエストは成功します。

この状態では、どのホストからでもGETリクエストであればアクセスできてしまうので、
接続するOriginを特定してみます。




http://176.34.47.135
GET
3000
*

ここで先程とはまた別のホストから同様にAjaxでリクエストしてみると、Preflightリクエストで403が返り、アクセスできないことがわかります。

今までは、S3のパーミッションはAWSアカウントを基準としたアクセス制御でしたが、このようにHTTPレベルでもアクセス制御ができるようになりました。

これによって、S3の使用の仕方がとても広がるのではないかと思います。

こちらの記事はなかの人(memorycraft )監修のもと掲載しています。
元記事は、こちら

三浦 悟

三浦 悟

高円寺在住のなんじゃ系男子 またの名をmemorycraftといいます。 炭水化物大好き 日々の「なんじゃ?」を記事にしてます。

cloudpack

cloudpackは、Amazon EC2やAmazon S3をはじめとするAWSの各種プロダクトを利用する際の、導入・設計から運用保守を含んだフルマネージドのサービスを提供し、バックアップや24時間365日の監視/障害対応、技術的な問い合わせに対するサポートなどを行っております。
AWS上のインフラ構築およびAWSを活用したシステム開発など、案件のご相談はcloudpack.jpよりご連絡ください。