简体   繁体   中英

How can i use a backend pre-signed url to upload files to Amazon S3 using its SDK?

I have a Rails backend and it returns to me a "signature" string, "objectKey" string and a "policy" string. I have to use these parameters to upload the file selected by the user, but i don't find any way to use these parameters instead of the "accessKey" and the "accessSecretKey" using the Amazon JavaScript SDK.

I already have a code that make the upload, but it is using the credentials directly, and it doesn't looks safe.

Anyone already faced this problem?

You can not upload an object with a presigned url. AWS has the solution in order to grant temporary credentials called AWS Security Token Service. The short name is AWS STS.

Requesting Temporary Security Credentials - AWS Identity and Access Management

For examples:

  1. An user accesses to your rails application.
  2. Your rails application issues and returns a temporary credentials using AWS STS.

     client = Aws::STS::Client.new policy = AWS::STS::Policy.new do |p| p.allow( actions: ['s3:PutObject'], resources: ['arn:aws:s3:::some-bucket/path/to/xxx*'], effect: 'allow' ) end token = client.get_federation_token(name: 'name', policy: policy.to_json, duration_seconds: 900) puts token.credentials.to_json # { # "access_key_id": "XXXXXXXXXXXXXXXXXXXX", # "secret_access_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", # "session_token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", # "expiration": "2016-03-25T00:46:20Z" # } 
  3. The user upload an object securely using the temporary credentials.

Note that when you use the temporary credentials, you have to authenticate with access_key_id, secret_access_key and session_token .

I did not found a solution for my problem with AWS Sdk for JavaScript.

Looks that, in our case, the workflow(signature/policy generation) is the same of the shown in this article https://aws.amazon.com/articles/1434

To solve this problem I replaced the Sdk to a simple XmlHttpRequest and a FormData object to push my files to s3. The payload could not be changed to keep compatibility with another parts of the app. Using this approach it's necessary to have an AccessKey, policy, signature, key(file key) and the file in the formData. Depending on how the policy/signature was generated, it's also necessary to add other fields to formData to get the things working. In this case, i've added a sucess_action_status.

The code to mount the formData:

  var formData = new FormData();
  formData.append('key', <KEY>);
  formData.append('AWSAccessKeyId', <ACCESS_KEY>);
  formData.append('policy', <POLICY>);
  formData.append('signature', <SIGNATURE>);
  formData.append('success_action_status', <SUCCESS_CODE>);
  formData.append('file', file, file.name);

With this form data, create a XMLHttpRequest like this

var request = new XMLHttpRequest();
request.open("POST","https://<YOUR BUCKET>.s3.amazonaws.com");
request.setRequestHeader("enctype", "multipart/form-data");

And send the request passing the formData object.

request.send(formData);

It's important to remember that the values in formData must respect the generated policy.

It's possible to get the upload process by adding this Listener:

request.upload.addEventListener('progress', function(e){
      console.log(e);
});

Thank you all for the help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM