Authenticate with web server before uploading/downloading file to AWS S3 - android

I want to create an android application and use AWS s3 as a storage service to allow the user to upload and download files. I have studied something about S3 REST service, which can help me achieve the same, after configuration of IAM Role for Bucket etc.
Now thing is, I want only the registered users of my application/ with access control configured at my web server(username/password) should be allowed to upload/download the file and not anyone with only app access should be allowed.
Look the link below as well, to have some idea about AWS S3 upload file using REST
http://www.tothenew.com/blog/file-upload-on-amazon-s3-server-via-rest-api-call/
Putting simply, in addition to that described in the link above, I just need the answer to the following questions:
1) How to allow only registered users?
2) Is it good practice to hard code AWS S3 secretKey etc in the production application.
3) Does hardcoding these values in my app could lead to a scenario where even an unregistered user of my application could be able to upload/download the file to aws s3?
All suggestions are welcome, if-if they solve part of the puzzle, as I am completely unaware of the solution
It would be very helpful...,
Thanks in advance,

For sure it is not best practice to hard code secret keys inside your codes..
Now if you want to separate the authorized and the unauthorized users one AW services that does this job and more is AWS Cognito . You can find a lot in the aws documentation https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-console.html
A few things for Cognito :
You have Amazon Cognito User Pools tha provides :
Sign-up and sign-in services.
A built-in, customizable web UI to sign in users.
Social sign-in with Facebook, Google, and Login with Amazon, as well as sign-in with SAML identity providers from your user
pool.
User directory management and user profiles.
Security features such as multi-factor authentication (MFA), checks for compromised credentials, account takeover
protection, and phone and email verification.
You have Amazon Cognito Identity Pools (Federated Identities) that provides :
Users in an Amazon Cognito user pool
Users who authenticate with external identity providers such as
Facebook, Google, or a SAML-based identity provider
Users authenticated via your own existing authentication process

This how it works in my application
Ask user register/login using aws cognito
deploy an api via api gateway that acts as proxy for S3 services
For the api , apply AWS cognito as Authorizer in api gateway
This however has a limitation on size of object
The option I have tried is use signed urls, and this is spit out by back end application upon registered users access requests.
My implementation includes below
1. Client requests signed urls using an api with a lambda implementation
2. Lambda generates signed urls and passes on the response.
3. while creating signed urls, key/id are used from a parameter store (see EC2 parameter store) secured against role and with a KEY.
I think from your use case , EC2 parameter store (instead of database) should be sufficient to securely keep secretes.

Related

How to grant access to android app users for AWS S3 Objects?

I have a bucket in Amazon S3 and I have Lambda functions that generates JSON files for this bucket. I am using the S3 files in my mobile app. Until recently, I gave public access to these S3 files for simplicity. But now I want these S3 objects to be accessible with a simple authentication. I’ve examined all AWS tutorials but couldn’t find an easy way to implement this. I don’t want to use Cognito service since my app doesn’t need authentication and since my S3 files are not user-related, they are used for app. I want these S3 objects to be accessible by http request to a url which includes simple key like this:
https://s3.eu-central-1.amazonaws.com/<bucket name>/<object name>?<key>
where key can be a combination of region, aws access key, secret access key or other values of the user that i define (I am using Retrofit to fetch json data from S3 bucket) I’ve looked at the presigned url option but an example for android-sdk doesn’t exists there, and most of the methods that can be used for this purpose are deprecated. Isn’t there an easy way for this? Or should I host my json files in other service/place?
If you say no to Cognito then you are just complicating things for yourself. This is exactly the case where you want to use Cognito. The fact that you don't require your users to authenticate and that the S3 content is not user specific doesn't mean that Cognito is not suitable in this scenario.
All you have to do is to create Cognito identity pool and choose to support unauthenticated entities. Create an IAM policy that allows reading from that specific S3 bucket and let unauthenticated users to assume that IAM role by attaching it to those unauthenticated entities.
Authentication then happens automatically during the initialization of SDK in your application. That is all that you need to do to allow access to that S3 bucket only from your application.
And you get access metrics even for unauthenticated users as a bonus. And if you later decide that you want your application to support authentication as well, then you don't need to change almost anything in your setup.

How to secure service account credentials in an Android application?

I have an android app which communicates with Google cloud api services like speech to text, translation, NLP etc. The application is using a service account to do this and the private key file is stored in the application itself. I understand that is a bad practice as anyone can see it using dissembler but I am not sure where else to store it for an android device.
The following post suggests to store this file on a build server:
https://brightinventions.pl/blog/securing-your-google-service-account-key-in-builds/
However, I think that it does not fix the issue as the service credential file is getting included in the publish package.
Please let me know if you can think of a solution.
Do not embed service account credentials in applications. Service Account credentials have a permanent lifetime which means you will be breached. You can delete service account credentials, but then you will have to re-release your application.
You have several options:
Implement Google OAuth so that your users authenticate with Google Accounts. When authenticating use the correct Google OAuth Scopes to provide temporary permissions.
Implement temporary access tokens. Your users will connect to your website, authenticate and your code will give them a temporary access token created from service account credentials. This access token will expire. The default is 3600 seconds but you can control this.
You users will make all requests thru your website API's. You control authentication of the users. Your website code then makes the API requests on behalf of the users. This is not an ideal solution as all traffic goes thru your website (Compute Engine, App Engine, etc.) and you will pay for that bandwidth.

AWS Cognito vs IAM role in Android APP for security aspects

An app of mine in the android playstore (let's say >1.000.000 installs) collect some anonymous statistics. I want to store and work with these statistics on an amazon EMR cluster.
Currently I use AWS Cognito for creating Unauthorized access for Uploading the data to S3/Firehose. For saving money I thought of changing this procedure to use a hardcoded IAM user, which only able to upload the data to FH/S3. I don't need the identification of each user.
What disadvantages should I expect in terms of security?
Cognito federated identities is 100% free. Switching to an IAM user won't save you money.
Per the pricing page: "Using the Federated Identities feature for authenticating users and generating unique identifiers is always free with Amazon Cognito."
I think if they somehow get access to your sourcecode they can upload data to s3/firehose . Actually I am in the same kind of dilema only I dont have an app on appstore yet but since the IAM i am using only has read access to a AWS service I dont really see issue with it. because If I am correct AWs does charge for every token refresh after 50.000 MAU if you use Cognito

How to use AWS S3 credentials in android for uploading contents

I am using AWS S3 to upload and store contents in my Android application. I am using the below code in a java file:
AmazonS3Client s3Client = new AmazonS3Client(
new BasicAWSCredentials("XYZ",
"ABC+wktN"));
But this seem to be easy to retrieve (even if the apk is signed!). I tried using progaurd but that crashes app on some mobiles devices (especially this AWS part).
Is there any approach where i can hide credentials in Code without anyone being able to retrieve it? Or has anyone used any other method? One option is to upload to a intermediate server and the server uploads it to AWS S3, but thats an extra hop. Another is make the app get credentials from server through an URL call instead of having the credentials on mobile, but if a hacker can get the credentials directly he can get the URL as well and get the key.
Amazon Cognito can help you solve the problem. You can use it to deliver temporary, limited-privilege credentials to your application. With Cognito
you don't have embed long lived credentials inside your app
you can retrieve temporary credentials from Cognito. In case credentials are intercepted, they are valid at most an hour (configurable).
you can attach access policy to the credentials to limit what resource the credentials can access. See Understanding Amazon Authentication Part 3 Roles and Policies.
Cognito supports integration with 3rd party identity providers like Facebook, Login with Amazon, etc. You can force customers authenticated before accessing your resource
Cognito also supports developer authenticated identity, so that you can build your own backend to authenticate customers.
You can find additional information their blog http://mobile.awsblog.com/blog/tag/amazon-cognito and the developer guide http://docs.aws.amazon.com/cognito/devguide/identity/.

Typical app user authentication using AWS

My main question is what is the typical way mobile apps authenticate users? I know that AmazonCognito is used to sync userdata once you receive a token, but that token is simply a set of access rules, right? Which has nothing to do with a particular user (just the fact that they are an authenticated user in general).
But before even that, there needs to be a way to authenticate a username/pass that the user signed up for so that you can retrieve the token. In almost all of the documentation, they use Facebook/Google/etc as examples of third party providers, and there IS an example of setting up your own 3rd party provider, but this all requires your own backend to service that. C
onsidering that there may be many users trying to user the app and authenticate, does it not seem like a bad idea to set up a backend somewhere else? And is there a way to integrate this part into AWS as well so that there is no custom backend work? How is this typically done?
Site node: I'm using Android SDK at the moment.
Thanks :)
AWS Cognito has two different purposes. One is to synchronize data as you described in your question.
The other one is to help to manage user identities and create the glue between external Identity Providers (your own, Facebook, Google or Amazon) and AWS.
Here is the workflow at high level. Details are available at http://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/cognito-auth.html
Using AWS Console, create a Cognito Identity Pool
Associate two IAM Policies to your Cognito Identity Pool. One for the unauthenticated users and one for authenticated users. Best practices is to grant least privileges to both category of users. The AWS Console will help you to go through these steps and will propose reasonable default values.
In your code, initialize your CognitoCredentialsProvider object as this
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
myActivity.getContext(), // get the context for the current activity
"AWS_ACCOUNT_ID",
"COGNITO_IDENTITY_POOL",
"arn:aws:iam::AWS_ACCOUNT_ID:role/UNAUTHENTICATED_ROLE",
"arn:aws:iam::AWS_ACCOUNT_ID:role/AUTHENTICATED_ROLE",
Regions.US_EAST_1
);
In your code, proceed as usual to authenticate your users (using your own provider or Facebook, Google or Amazon)
When you will receive the token issued by the Identity Provider, associate it to Cognito. The Cognito SDK will transparently trade this token for a temporary AWS Access Key, Secret Key that service clients can use.
Give the credentials provider to your service client object, such as
AmazonDynamoDB client = new AmazonDynamoDBClient(credentialsProvider);
This approach allows you to avoid to deploy your own backend as broker to AWS services. Most service calls can be made directly from the mobile app, allowing a good level of scalability at a low cost.
Backend of your own is only required to offload some computing task of your mobile devices or if you want to implement your own Identity provider and make it interact with Cognito (see detailed workflow at http://mobile.awsblog.com/post/Tx2FL1QAPDE0UAH/Understanding-Amazon-Cognito-Authentication-Part-2-Developer-Authenticated-Ident)

Categories

Resources