HTML
JavaScript
Node.js
AWS
S3

POST (AWS 署名バージョン 4) を使用したブラウザベースのアップロードについて

  • 公式ドキュメントが具体的に例示するつもりがなさそうなので、実際に実装した物を書く。これも説明を一部すっ飛ばしてます。
  • このドキュメントは、実際に動いたものを例示することを目的として書かれています。
  • 簡単のため、リージョンは ap-northeast-1 の決め打ちで書いています。
  • 日付は 20180214(2018年2月14日)としています。これも適宜書き換えてください。

policy と x-amz-signature の算出方法

exports.handler = function (event, context) {

    var key = "シークレットキー"
    var dateStamp = "20180214"
    var regionName = "ap-northeast-1"
    var serviceName = "s3"


    const policy = {
        "expiration": "2025-12-30T12:00:00.000Z",
        "conditions": [
            { "bucket": "バケット名" },
            ["starts-with", "$key", ""],
            { "acl": "public-read" },
            //{ "success_action_redirect": "http://sigv4examplebucket.s3.amazonaws.com/successful_upload.html" },
            //["starts-with", "$Content-Type", ""],
            { "x-amz-meta-uuid": "14365123651274" },
            { "x-amz-server-side-encryption": "AES256" },
            //["starts-with", "$x-amz-meta-tag", ""],

            { "x-amz-credential": "アクセスキー/" + dateStamp + "/" + regionName + "/s3/aws4_request" },
            { "x-amz-algorithm": "AWS4-HMAC-SHA256" },
            { "x-amz-date": "20180214T000000Z" }
        ]
    };


    var stringify = JSON.stringify(policy);

    sigver = "AWS4"
    hashalg = "sha256"

    const cryp = require("crypto");

    var dateKey = cryp.createHmac(hashalg, sigver + key).update(dateStamp).digest()
    var dateRegionKey = cryp.createHmac(hashalg, dateKey).update(regionName).digest()
    var dateRegionServiceKey = cryp.createHmac(hashalg, dateRegionKey).update(serviceName).digest()
    var signingKey = cryp.createHmac(hashalg, dateRegionServiceKey).update("aws4_request").digest()

    var policy64 = new Buffer(stringify).toString('base64') // これが policy
    var signature = cryp.createHmac(hashalg, signingKey).update(policy64).digest('hex')


    console.log(signature.toString()) // これが x-amz-signature


    context.done(null, policy64 + "/" +  signature);
};

HTML側の記述

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head><body>
<form method="post" action="https://s3.ap-northeast-1.amazonaws.com/バケット名/" enctype="multipart/form-data">

<p>

key <input type="text" name="key" value="uploadedObject" /><br/>
acl <input type="text" name="acl" value="public-read" /><br/>
xmuid <input type="text" name="x-amz-meta-uuid" value="14365123651274" /> <br/>
 xsse <input type="text" name="x-amz-server-side-encryption" value="AES256" /> <br/>
buc <input type="text" name="bucket" value="バケット名" /><br/>
poli <input type="text" name="policy" value="算出された policy" /><br/>
xal <input type="text" name="x-amz-algorithm" value="AWS4-HMAC-SHA256" /><br/>
xcre <input type="text" name="x-amz-credential" value="アクセスキー/20180214/ap-northeast-1/s3/aws4_request" /><br/>
xdate <input type="text" name="x-amz-date" value="20180214T000000Z" /><br/>
xsig <input type="text" name="x-amz-signature" value="算出された x-amz-signature" /><br/>

フォーム構成要素の一番最後に input.file を書くこと

<input type="file" name="file"></p>

<p><input type="submit" value="送信する"></p>

</form>
</body>
</html>

大体こんな感じ。