Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending file direct from browser to S3 but changing file name

I am using signed authorized S3 uploads so that users can upload files directly from their browser to S3 bypassing my server. This presently works, but the file name is the same as on the user's machine. I'd like to save it on S3 as a different name.

The formdata I post to amazon looks like this:

var formData = new FormData();
formData.append('key', targetPath);                       // e.g. /path/inside/bucket/myFile.mov
formData.append('AWSAccessKeyId', s3Auth.AWSAccessKeyId); // aws public key
formData.append('acl', s3Auth.acl);                       // e.g. 'public-read'
formData.append('policy', s3Auth.policy);                 // s3 policy including ['starts-with', '$key', '/path/inside/bucket/']
formData.append('signature', s3Auth.signature);           // base64 sha1 hash of private key and base64 policy JSON
formData.append('success_action_status ', 200);           // response code 200 on success
formData.append('file', file.slice());                    // e.g. /path/on/user/computer/theirFile.mov

However instead of the file ending up at: https://s3.amazonaws.com/mybucket/path/inside/bucket/myFile.mov

It ends up as: https://s3.amazonaws.com/mybucket/path/inside/bucket/theirFile.mov

Note it has their filename but my base path.

I would like it to have the filename I specify as well.

UPDATE: Update: this was working all along I simply had other code that copied from one bucket to another that restored the original file name and thus confusing me.

like image 689
Aaron Silverman Avatar asked Oct 15 '14 15:10

Aaron Silverman


1 Answers

Are you sure about the contents of targetPath and where that data comes from?

The behavior you are describing is what should happen in one particular case where targetPath doesn't actually contain /path/inside/bucket/myFile.mov.

I would suggest that targetPath actually contains the value /path/inside/bucket/${filename} -- and by that I mean, literally, the characters $ { f i l e n a m e } are at the end of that string, instead of the filename you intend.

If that's true, that's exactly how it's supposed to work.

If you do not know the name of the file a user will upload, the key value can include the special variable ${filename} which will be replaced with the name of the uploaded file. For example, the key value uploads/${filename} will become the object name uploads/Birthday Cake.jpg if the user uploads a file called Birthday Cake.jpg.

— https://aws.amazon.com/articles/1434

If you populate that variable with the literal filename you want to see in S3, then the uploads should behave as you expect, using your filename instead of the filename on the uploader's computer.


Also, a more secure approach would be to eliminate the key 'starts-with' logic in your policy, and instead explicitly sign a policy (dynamically) for each upload event, with the specific key you want the user to upload. Otherwise, it's not impossible to exploit this form to to overwrite other files within the same key prefix.

like image 176
Michael - sqlbot Avatar answered Oct 26 '22 23:10

Michael - sqlbot