1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS SDK for JavaScript v3 (AWS Signature V4)におけるPresigned-URLの署名対象

Posted at

Presigned-URLの発行

S3にPUTできるPresigned-URLを発行する
発行はAWS SDK for JavaScript v3 (AWS Signature V4)にて行うこととする。

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const client = new S3Client({
    region: 'xxxx',
});
const command = new PutObjectCommand({
    ExpectedBucketOwner: '123456789012',
    Bucket: 'example',
    Key: 'foo/bar.png',
    ContentType: 'image/png',
    ContentLength: 1234,
    ContentMD5: 'abc123abc/123abc123abc==',
});
const url = await getSignedUrl(client, command, {
    expiresIn: 60,
});
console.log(url);

当然、問題無くPUTできる。

curl -v \
     -X PUT \
     -H 'content-type: image/png' \
     -H 'content-length: 1234' \
     -H 'content-md5: abc123abc/123abc123abc==' \
     --upload-file 'bar.png' \
     'https://example.s3.xxxx.amazonaws.com/foo/bar.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIXXX&X-Amz-Date=20230101T123456Z&X-Amz-Expires=60&X-Amz-Security-Token=XXXXX&X-Amz-Signature=abc123&X-Amz-SignedHeaders=content-length%3Bcontent-md5%3Bhost&x-amz-expected-bucket-owner=123456789012&x-id=PutObject'

Presgined-URLの署名対象

Presgined-URLのQUERY_STRINGに注目してみると、

X-Amz-SignedHeaders=content-length%3Bcontent-md5%3Bhost

となっている。
ヘッダーにおいてはcontent-lengthcontent-md5hostに対してしか署名されていない雰囲気が伝わってくる……。

PUTヘッダー値の操作

ということで、

  • その他ヘッダーを付与する
  • content-type 値を任意のものにする

ことが可能であるため、

curl ... \
     -H 'cache-control: no-cache' \
     -H 'content-type: image/jpeg' \
     ...

などとヘッダー情報を書き換えても問題無くPUTでき、PUTされたS3オブジェクトのメタデータは実際にその通りになる。

※注:x-amz-*ヘッダーは署名しなければ追加できない。

特に影響が大きいケース

このS3バケットをCloudFront経由もしくは直接的に公開している場合は、

  • CloudFrontのキャッシュ挙動が、CloudFront側キャッシュポリシーとS3オリジン(当S3オブジェクト)側キャッシュ関連ヘッダーの状態に合わせて変わること
  • 閲覧ユーザー(クライアント)へのレスポンスにそのまま適用されること

などの理由により、例示のヘッダー操作影響は特に大きくなる。

調整方法

パターン1

ヘッダーと値をセットしつつ、署名対象ヘッダーを指定する

これにより、ヘッダー情報を書き換えてPUTしようとすると失敗することになる。

...;
const command = new PutObjectCommand({
    ...,
    CacheControl: 'max-age=60',
    ContentType: 'image/png',
    ...,
});
const url = await getSignedUrl(client, command, {
    ...,
    signableHeaders: new Set([
        'cache-control',
        'content-type',
    ]),
});
...;
X-Amz-SignedHeaders=cache-control%3Bcontent-length%3Bcontent-md5%3Bcontent-type%3Bhost

パターン2

ヘッダー情報を書き換えたPUTは許容するが、PUTされた後のS3オブジェクトを、メタデータを上書き(別キー or 同キーでのオブジェクトコピー)してから利用する。

MetadataDirective.REPLACEが文字通りメタデータ全体を「REPLACE」するため、他にも独自メタデータがあった場合は、それらも全て列挙する必要がある(そう言われるとMetadataDirective.COPYを使いたくなるかもしれないが、強制上書きにならないので力不足)。

import { S3Client, CopyObjectCommand } from '@aws-sdk/client-s3';
const client = new S3Client({
    region: 'xxxx',
});
const command = new CopyObjectCommand({
    ExpectedBucketOwner: '123456789012',
    CopySource: 'example/foo/bar.png',
    Bucket: 'example',
    Key: 'foo/baz.png',
    MetadataDirective: 'REPLACE',
    CacheControl: 'max-age=60',
    ContentType: 'image/png',
});
const ret = await client.send(command);
console.log(ret);

おまけ:ファイルPUT

import { createReadStream } from 'node:fs';
import fetch from 'node-fetch';
const res = await fetch(url, {
    method: 'PUT',
    headers: {
        'cache-control': 'max-age=60',
        'content-type': 'image/png',
        'content-length': 1234,
        'content-md5': 'abc123abc/123abc123abc==',
    },
    body: createReadStream('bar.png'),
});
const body = await res.text();
console.log({
    status: res.status,
    statusText: res.statusText,
    body: body,
});

パラメーターを色々と変更しながら、Presigned-URL発行からファイルPUTまで一気に実行してみると、挙動が分かり易い。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?