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 )監修のもと掲載しています。
元記事は、こちら