aws-sdk-js icon indicating copy to clipboard operation
aws-sdk-js copied to clipboard

getSignedUrl - POST support

Open anarkrypto opened this issue 2 years ago • 3 comments

In S3, direct-upload through pre-signed url don't have params for limiting the size of upload content, since it seems to be only valid for POST, not PUT.

This allows users to upload files that are much larger than expected. Attackers can bypass front-end check. Post-treatment does not seem to be an efficient practice.

I found some posts about such a feature (#1252 and #643), but they were abandoned and closed a few years ago.

However, support in python (boto3), Java and Go cli is mentioned.

I would like to apply the "content-length-range" in Conditions, as I can do in boto3.

Is there any possibility of implementing POST in aws-sdk-js and therefore these additional conditions ?

Thank you!

anarkrypto avatar Apr 01 '22 08:04 anarkrypto

This is quite appalling that something as important as this has gone under the radar and is not being actively developed.

amirali26 avatar Apr 18 '22 20:04 amirali26

Is it possible to call createPresignedPost for 'uploadPart'? I try to create a large file loading system that generates signed links for each party, but to add security I need to indicate the size of each part (Content-Length).

albertochigua avatar May 06 '22 06:05 albertochigua

I think It is possible now by using: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/modules/_aws_sdk_s3_presigned_post.html

mjpolak avatar May 31 '22 17:05 mjpolak

Thank you @mjpolak, it worked. Here's an example of usage:

Server code

import { createPresignedPost } from '@aws-sdk/s3-presigned-post'
import { S3Client } from '@aws-sdk/client-s3'

const client = new S3Client({
	region: 'us-east-1',
	credentials: {
		accessKeyId: process.env.AWS_ACCESS_KEY_ID as string,
		secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY as string,
	},
})

async function GeneratePreSigned () {

	const filename = 'image.png'
	const Bucket = 'myucket'
	const Key = 'images/' + filename
	const Expires = 900 // 15 minutes
	const Fields = {
		acl: 'public-read',
	}

	const Conditions = [
		{ acl: 'public-read' },
		{ bucket: Bucket },
		['starts-with', '$key', Key],
		['content-length-range', 0, 1024 * 1024 * 5], // max 5MB
	]

	const { url, fields } = await createPresignedPost(client, {
		Bucket,
		Key,
		Conditions,
		Fields,
		Expires,
	})

	return { url, fields }
}

Client example with React

<form action={url} method="post" encType="multipart/form-data">
	{Object.keys(fields).map(key => (
		<input type="hidden" name={key} value={fields[key]} />
	))}
	File:
	<input type="file" name="file" />
	<input type="submit" name="submit" value="Upload to Amazon S3" />
</form>

anarkrypto avatar Mar 10 '23 08:03 anarkrypto