結論まで言ってしまった。
そう、presignedpostを使えばできる。
はじめに
私がはじめてpresignedurlと出会ったのは、apigatewayやlambdaのペイロードの容量制限(それぞれ10MBと6MB)によって、lambdaのreturnからs3のファイルを取得することができなかったとき。
こんな時みたいに大きい容量のファイルをダウンロードやアップロードする際に便利なのがpresignedurlだ。便利で使い勝手がいい。だってどんなに大きいファイルでもポンポンs3にぶち込めてしまうだもの。
でも、このurl、入力サイズに制限がない。だからめちゃくちゃでっかいサイズのファイルをs3に直接アップロードできてしまう。そのurlを知っている人なら誰でもね。
そうなのだ、もしそのurlが漏洩してしまったら巨大なファイルをアップロードする攻撃が可能になってしまう。チョットコワイ。
そんなあなたに贈るものがpresignedpostである。presignedurlの機能をほぼそのままに、ファイルサイズ制限をつけることができる優れものなのだ。
使い方
BucketとKey、ExpiresInを指定するのはpresignedurlと一緒。
presignedpostはConditionsというパラメータが追加されて、様々なメタ情報をurlに付与することができる。
例えば以下のように記述すると、入力サイズが0~1000bytesであるファイルのみを受け付けるurlを発行することができる。そのほかはpresignedurlで発行した場合と同じである。実に素晴らしいことではないか。
少し沼ポイントなのが、アップロードしたいデータは、generate_presigned_post()
の返値fields
の、一番最後に、key名をfile
として配置しなくてはならないことだ。
s3 = boto3.client('s3', config=Config(signature_version='s3v4'))
res = s3.generate_presigned_post(
Bucket="bucket-name",
Key="key_name",
Conditions=[["content-length-range",0,1000]],
ExpiresIn=3600,
)
url = res["url"]
fields = res["fields"]
fields["file"] = json.dumps("やっほー") #アップロードしたいデータ
requests.post(url=url, files=fields)
boto3.client.generate_presigned_post()
は、以下のようにpost用のurlとその他認証情報の辞書を返す。
{
'url': 'https://bigdata-test10.s3.amazonaws.com/',
'fields': {
'key': 'key_name',
'x-amz-algorithm': 'AWS4-HMAC-SHA256',
'x-amz-credential': 'ASIA**********',
'x-amz-date': '20211226T022115Z',
'x-amz-security-token': '************',
'policy': '************',
'x-amz-signature': '************'
}
}
おわりに
presignedpostは、入力サイズなどの様々な制限を付与できるpresignedurlと思っていて差し障りないと思われる。
今回はcontent-length-range
にのみ触れたが、他にもコントロールできるメタ情報はたくさんある。
以下を参考にされたい。
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.generate_presigned_post
https://advancedweb.hu/differences-between-put-and-post-s3-signed-urls/