Appearance
S3 Presigned URLによるアップロードサイズ上限の設定
本記事ではS3 Presigned URLを利用したファイルアップロードにおいて、アップロードサイズの上限を制御する方法について解説します。
Presigned URLは便利な仕組みですが、そのままではアップロードサイズを制限できません。 そこでSigV4の署名対象に Content-Length を含めることでサイズ制限を実現する方法を説明します。
Presigned URLとは?
Presigned URLは一定時間だけ有効なS3操作用の署名付きURLです。 これを利用するとクライアントはバックエンドを経由せずにS3へ直接アクセスできます。
Presigned URLではアップロード(PUT / POST)・ダウンロード(GET)の両方が可能です。 アップロード時の典型的なフローは以下の通りです。
アップロードサイズ上限を設ける方法
Webシステムにおいてユーザーがアップロードするファイルのサイズ制限は一般的なユースケースです。 しかしPresigned URLはクライアントに直接アップロードを委譲する仕組みのためバックエンドが実データを検査できません。
このような制約がある中でもSigV4の仕組みを利用することでアップロードサイズを制御することができます。 具体的には Content-Length ヘッダーを署名に含めることで指定したサイズのリクエストのみを受け付けるようにできます。
SigV4におけるヘッダー署名の仕組み
Presigned URLでは X-Amz-SignedHeaders によってどのヘッダーを署名に含めたかが明示されます。
例: X-Amz-SignedHeaders=host;content-length
この場合 content-length は署名対象になり署名時のサイズと実際のリクエストのサイズが一致しない場合SignatureDoesNotMatch で拒否されます。
サイズ制限をするフロー
以下の手順でサイズを制限できます。
- クライアントからサイズを送る
- バックエンドでバリデーション
- Content-Length を署名に含める
- クライアント側アップロード
アップロード時の偽装可能性について
ここで気になるのがS3へのアップロード時に Content-Length を偽装できるのかという点です。
結論として偽装は成立しません。
Content-Length はHTTPプロトコル上「これから送信するボディのサイズ」を示すヘッダーです。 サーバー(S3)はこの値に従ってリクエストボディを読み取るため、宣言したサイズ以上のデータを送信してもそれ以上は受け付けられません。 つまり小さい値を指定して大きなファイルを送ろうとしても、途中で切り捨てられるかリクエスト自体が異常として扱われます。
結果としてアップロード時に Content-Length を偽装して想定より大きなファイルをアップロードすることはできません。 このため Content-Length を署名に含めることで、アップロードサイズは実行時にも厳密に制御されます。
まとめ
- Presigned URLはアップロード・ダウンロード両方に利用可能
- アップロードサイズ制限は非常に一般的なユースケース
Content-Lengthを署名することでサイズ制御が可能Content-Length偽装による制限回避は成立しない