S3で地図タイルのアクセス制御

S3に保存した地図タイルへの直呼び出しのアクセス管理ができないか検討

アクセス制御方式

http://www.tdn.co.jp/techblog/201207/55/
s3でのアクセス制御の方法は4種類らしい。
ACLbucket policy、IAM、Query String Request

自分なりの解釈
ACL:ファイルパーミッション
bucket policy:.htaccessのようなもの
IAM:ユーザーグループのようなもの
Query String Request:Oauth認証のようなもの

地図タイルへのアクセス制限

目的:地図タイルへの直アクセスを制御したい。

  • 直アクセスできるのは、許可したサイト、アプリ、ソフトから

方法:

  1. Refererを参照してアクセス解析。申請してもらったサイト以外からアクセスが頻発する場合は、bucket policyでブロック
  2. 申請してもらったサイトをbucket policyで許可
  3. Query String Requestのキーを発行して、それを利用してアクセス

Refererによるアクセス制御

http://www.idupree.com/dreams/s3-referer-hotlink
s3のbucket policyに以下を設定
refererが無い場合(index.htmlの読み出し)と、許可した所。※下の不具合でもっとシンプルな設定が動作しないと勘違いしていたかもしれないので、そっちを試した方がいいかも。あとで。

{
	"Version": "2008-10-17",
	"Id": "refererGuard",
	"Statement": [
		{
			"Sid": "1",
			"Effect": "Allow",
			"Principal": {
				"AWS": "*"
			},
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::ecoris/*",
			"Condition": {
				"StringNotLike": {
					"aws:Referer": "*"
				}
			}
		},
		{
			"Sid": "2",
			"Effect": "Allow",
			"Principal": {
				"AWS": "*"
			},
			"Action": "s3:GetObject",
			"Resource": "arn:aws:s3:::ecoris/*",
			"Condition": {
				"StringLike": {
					"aws:Referer": "http://ecoris.s3-website-ap-northeast-1.amazonaws.com/*"
				}
			}
		}
	]
}
不具合?

ACLでタイルをpublicにしていると、上記のRefererを設定してもアクセス制御できないみたい。
なので、以下コマンドでACLを削除。(全部まとめて変更はkillされたので、レベルごとに実行した)
s3cmd --recursive setacl --acl-private s3://ecoris/vegetation/tiles/1/

アプリ、ソフトからのReferer

アプリ、ソフトから地図タイルを呼び出した場合、No Refererになるっぽい。
それだとアクセス制御できないので、なんとかしたい。
Google Analytics SDKを使ってもらえば、refererが付く?
http://murapong.hatenablog.com/entry/20111220/1324379177

Refereは偽装できるので、うーん。

Query String Requestのテスト

http://www.tdn.co.jp/techblog/201207/55/
アクセスキーの発行とかは、管理が面倒そうなので現実的ではないけど、一応テスト

<html>
<head>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"></script>

<script>
    var AWSAccessKeyId='hoge';
    var secretAccessKey='hogehoge';
    var host = "https://s3-ap-northeast-1.amazonaws.com";
    var filePath = "/ecoristest/test/test.png";

    function myinit(){
     
     var dateTime = Math.floor(new Date().getTime()/1000) + 300; 
     var stringToSign = "GET\n\n\n" + dateTime + "\n" + filePath;
     var signature = CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA1(stringToSign, secretAccessKey));
    
     var url = host + filePath + "?AWSAccessKeyId=" + AWSAccessKeyId + "&Signature=" + encodeURIComponent(signature) + "&Expires=" + dateTime;
     document.getElementById("AuthenticationURL").innerHTML = "<a href='" + url + "'>access</a>";
    }

</script>
</head>
<body onload="myinit()">
<div id="AuthenticationURL"></div>
</body>
</html>

結論

他サイトからの直アクセスはRefererで対応。ただしReferer偽装できる。
アプリからの直アクセスは、Refererを設定してもらう。

一定ズーム以上をprivateにしておき、許可を与えたところからだけアクセス可にするなら
Query String Requestを設定してもいいかも。