hachpai
hachpai

Reputation: 306

Rails Activestorage and S3, storing sensitive data

ActiveStorage makes possible to upload and access files directly on S3 through the user browser in JS. Does it means that your S3 credentials are embedded into the user browser? I think I misunderstand that, that would make your credentials almost public...

In that case the only thing that prevents anybody to access other users data is the unique token generation. But 24-bytes random key can easily be bruteforced. Should I enforce security by implementing a unique key per user related to its own data?

What would be a good security architecture?

Upvotes: 1

Views: 2241

Answers (3)

Tarek N. Elsamni
Tarek N. Elsamni

Reputation: 1837

A good security architecture and probably this is what's implemented in ActiveStorage is:

1- A page including an upload form is requested.

2- A blob record will be created at the server side and persisted to the database (even before any upload happens). https://github.com/rails/rails/blob/0718c75bc2a7378d30e729a3c1d25ceb99400b7b/activestorage/app/models/active_storage/blob.rb#L70

3- The server call the 3rd party cloud service (AWS S3 for ex.) in the backend and issue a presigned url using the AWS credentials (secret credentials and should not be exposed to public) to be used for upload. https://github.com/rails/rails/blob/master/activestorage/lib/active_storage/service/s3_service.rb#L87

https://www.rubydoc.info/github/aws/aws-sdk-ruby/Aws%2FS3%2FObject:presigned_url

4- The server renders the page with the form and the presigned_url embedded.

5- The frontend at this point will have that presigned_url generated at the server and rendered into the form.

6- Javascript will capture this presigned_url from the html DOM and use it to make the upload.

7- After the upload, the javascript will have signed_id which will be posted in the form to the backend to update the blob record and mark it as uploaded (the one that was created in step1).

Pros:

1- You don't need to go through the server to upload any file and that means you are not blocking any processes during the upload and using the client computing power to handle such simple task.

2- You can upload even if the backend is down.

3- Faster user experience (less round trips).

Cons:

1- The temp token can be used by anyone that has access to it to upload.

2- The presigned_url has validity (expires_at) period and if the browser kept idle for some long time before doing the actual upload, the browser will probably get an auth error. It might need to issue a new temp token from the server!?

Note:

  • Generated presigned_url can have restricted access to specific folder/scope based on authenticated user or they can be privileged to access the whole bucket/no-scope if the uploaded blobs are public by business requirement.

This is how signed uploads works :)

Upvotes: 7

When you are using ActiveStorage with S3. You need to store credentials in environment variables as such

You need to create a file storage.yml

amazon:
  service: s3
  access_key_id: ENV["AWS_ACCESS_KEY_ID"]
  secret_access_key: ENV["AWS_SECRET_KEY"]
  region: ENV["AWS_REGION"]
  bucket: ENV["S3_BUCKET"]

Upvotes: -1

Timmy Von Heiss
Timmy Von Heiss

Reputation: 2218

Your S3 credentials should be saved as environmental variables in your repo, not hard coded. There is an example in Hartls book The Rails Tutorial.

Upvotes: 0

Related Questions