4

Our mobile app will be uploading images to AWS S3. The question is whether to do one of the following options:

  1. Upload the image to our APIs server, then our APIs server uploads the image to S3
    Pros: More secure, as the S3 credentials is only stored at cloud.
    Cons: More pressure on APIs server, as thousands of users will be uploading images, with sizes varying from 2 MB to 10 MB

  2. Let the mobile app upload the image directly to S3, by getting temp S3 credentials from APIs server for each S3 access.
    Pros: Less pressure on API's server, no files will be uploaded to the server.
    Cons: Less secure, as S3 credentials will be exposed to the mobile, regardless the fact, that the mobile app will ask for temp credentials each time to access S3, and that it gets the credential through SSL connection with the APIs server.

So, is option two above still better? As we are already granting temp credentials that is valid for only 15 minutes each time to access S3 through SSL connection.

What is the recommended way to do this?

  • What is your API authentication protocol in place? If you have an existing API authentication mechanism in place then extending API server capability to proxy incoming calls to s3 API calls (without storing it locally) may be possible unless you have very low response time requirement. – jhash Mar 8 '17 at 23:48
1

I'm not sure that there's a recommended practice, but I think it instead has to do with the requirements of the application and balancing the pros and cons.

Would it be a low server load? Ok, we can use the server to work with S3, it's obviously the preferred method (and it also keeps the interaction on the same API as the rest of your app service).

Would it be too heavy a load for the server? Ok, alternatives are to scale the server resources, or to see if the risk of having the app work directly with S3 is acceptable.

Is the information sensitive? Can we reasonably secure it if the app were to communicated directly with S3? If it's not highly sensitive and it can be reasonably secured and the risk is less than the cost of scaling the server to handle the loads, then this may be your choice.

The information is highly sensitive and terrible things would happen if the S3 key were sniffed out of SSL or from the device? In that case, it might be worth spending the money on scaling the server architecture.

I don't think there's any one single recommended way... naturally it's more secure to handle S3 from your server only (and you ask this in a security forum, so I assume that's your main focus), but all in all it becomes a balance driven by the requirements of the application.

1

A good way to implement it is generate temporary credentials that can only upload to a specific bucket portion (the one that the user has access).

Even in the event those credentials get stolen from memory (I suppose you use https for every comunication, so they cannot be stolen during transmission), a final user can only use them for what they were intended: uploading files.

An example of this is presented here

{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Effect":"Allow",
         "Action":"s3:PutObject",
         "Resource":"arn:aws:s3:::my_corporate_bucket/uploads/widgetco/*"
      },
      {
         "Effect":"Deny",
         "NotAction":"s3:PutObject",
         "Resource":"arn:aws:s3:::my_corporate_bucket/uploads/widgetco/*"
      },
      {
         "Effect":"Deny",
         "Action":"s3:*",
         "NotResource":"arn:aws:s3:::my_corporate_bucket/uploads/widgetco/*"
      }
   ]
}

I'd suggest you also periodically check all files in your bucket by verifying allowed extensions/file signatures (be careful, this may become really time consuming). You could also rescrict your policy more, based on file extensions (source here)

{
  "Id": "Policy1464968545158",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1464968483619",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::<yourbucket>/*.jpg",
      "Principal": "*"
    },
    {
      "Sid": "Stmt1464968543787",
      "Action": [
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::<yourbucket>/*.png",
      "Principal": "*"
    }
  ]
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.