I have a security question around setting up a mobile app with AWS as a backend. To get started with the mobile SDK you need an awsconfiguration.json, which contains AppClientId and AppClientSecret. Though according to the documentation, it says best practices are to "Manage your access keys as securely as you do your user name and password.". Furthermore if you were to look inside an IPA/APK file you would easily be able to extract these keys. My question is - does this really matter? What are the security risks? I know they are used to sign requests, so could anyone use these keys to sign arbitrary requests? I have the user pool setup to only allow an authenticated user to invoke a lambda function.
3 Answers
YOUR QUESTIONS
To get started with the mobile SDK you need an awsconfiguration.json, which contains AppClientId and AppClientSecret.
From the moment you ship a secret in the binary of a mobile app, you must consider it as belonging to the public domain, thus not a secret anymore, because it's up for grabs by attackers, and subject to be reused and abused in order to make requests to your backend in behalf of your mobile app, the what in the request, and your authenticated user, the who in the request.
The list of open source and paid tools that make easy to attack your mobile app is endless, but you can see a list of a few of them in my personal Github gist.
Furthermore if you were to look inside an IPA/APK file you would easily be able to extract these keys. My question is - does this really matter?
Depends in how much you value the data that can be delivered through your backend endpoints,and how much money you are willing to pay in AWS bills.
Has you say, secrets are easy to find by static analysis of your mobile app binary, but you can make them much more hard to find, and in this Github repo for a simple Android demo app, you can see here the use of native C code to hide the API Key. You can find more info in the official docs from Google, here and here.
What are the security risks? I know they are used to sign requests, so could anyone use these keys to sign arbitrary requests?
Even if the above JNI technique may deter a lot of less skilled attackers from stealing your AWS secrets, you must bear in mind that during runtime an attacker can use an instrumentation framework, like Frida, to hook into your code and extract any secret from it. So no matter how you hide it, even if encrypted, the attacker just needs to find the function that returns or uses the secret unencrypted to be able to extract it, and send it to a remote control server, from where they can reuse it to sign the requests to your AWS backend on behalf of your mobile app, therefore spoofing what it's making the request, thereby the reply to your question it's yes.
I have the user pool setup to only allow an authenticated user to invoke a lambda function.
This user pool will identify the authenticated user, by other words the who in the request, but it is not able to identify/authenticate what is making the request.
Think of the what as if the request is being made by your genuine mobile app, exactly as you uploaded it to the app store, or it's a modified version of it, one being instrumented by Frida or similar framework, or its a request from Postman or Curl.
POSSIBLE SOLUTION
I would recommend you to use the AWS API gateway in conjunction with a Mobile App Attestation solution to identify/authenticate what is making the request in behalf of the who, your authenticated user, and as already suggested, I would use AWS STS tokens for the authenticated user:
You can use the AWS Security Token Service (AWS STS) to create and provide trusted users with temporary security credentials that can control access to your AWS resources.
GOING THE EXTRA MILE
I always like to recommend the excellent work and effort that OWASP puts in helping developers with security of their applications, therefore I would recommend you the Github repo OWASP - Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.

- 11,244
- 3
- 43
- 57
-
Very good explanation! I guess my only question is what is the point of the clientId/clientSecret and why do all the mobile app samples insist that you use them? When creating a user pool app client these are the two main things you need. If using Amplify framework, you need the awsconfiguration.json, which was those keys. And why can I not find any samples using STS in a mobile app (I struggle navigating the AWS documentation). Thanks again for all your help! – Nelson.b.austin Jan 10 '20 at 13:54
-
Its all about defense in depth, you must apply as many layers as possible to make it so difficult to the point the attacker will prefer to move to an easier target. Just like a medieval castle have several layers of defense or like a high security prison, that makes harder for a prisoner to escape, when compared to a normal prison. About code examples they always go for the route of less friction for developer adoption, not necessarily to the most secure one, and then they use disclaimers saying that for production you must take a more secure approach. And yes AWS docs are a pain to navigate. – Exadra37 Jan 10 '20 at 14:06
You need to secure it in two steps
1) you need to create a logic to encode and decode your credentials
Best Place to Store Included AWS Credentials in an iOS Application
2) now the SDK allows passing a JSONObject containing the configuration from the awsconfiguration.json file. You can store the information in JSONObject in your own security mechanism and provide it at runtime through the constructor.

- 4,420
- 1
- 9
- 22
If you hard code IAM keys into your application (which is generally not advisable), do it with the assumption that anyone in the world will be able to use these credentials. Lock those permissions down to the point where you could comfortably post them to reddit.
The real answer is to use AWS cognito identities to generate STS tokens for a given role, and have the role with the permissions you need. This allows you to have an audit trail (of sorts) for each individual user. It allows you to disable registration or kill the permissions of individual users without breaking the app for everyone else. It allows you to have different users have different permissions in much more controllable and scalable way.
The problem with hard-coded API keys in your app is that you can't granular revoke permissions if you discover a vulnerability or abuse without possibly breaking the app for everybody. You can't rotate the API keys without pushing out a software update (and how often do your users update, really?). And most of all, you can't track requests at all, you just know when the API keys are abused (and I think cloudtrail will give you the calling IP address if you can make use of that), and any change you make will affect all of your users immediately.
There is documentation here with example apps and quick start guides to get you up and running with Cognito: https://aws.amazon.com/cognito/dev-resources/

- 420
- 6
- 17
-
Are the Cognito UserPool AppClientId and AppClientSecret the same as IAM keys? These are the credentials I am talking about. I'm authenticating to Cognito Identity Pool and have an Authenticated Role that only allows logged in users to invoke certain lambda functions. – Nelson.b.austin Jan 09 '20 at 00:33
-
Yes they are, except that they expire and have to be renewed (which is handled by the sdk), and they map to roles. You shouldn't have to store credentials in the app itself, the temporary keys should be stored in memory. There are a couple of workflows, the one with which I'm most familiar is having the user auth to an identity provider (Google, Facebook, etc.) and then using that trust to get an openid token from cognito. Then using that token to generate temporary api keys (a la assumeRoleWithWebIdentity call) as needed. I think the token can be safely stored on disk. – TopherIsSwell Jan 09 '20 at 01:02
-
more info: https://docs.aws.amazon.com/cognito/latest/developerguide/authentication-flow.html – TopherIsSwell Jan 09 '20 at 01:02
-
I'm still very confused. Even in the aws-sdk-android-samples they provide the cognito_client_id/secret - https://github.com/awslabs/aws-sdk-android-samples/blob/master/AmazonCognitoAuthDemo/app/src/main/res/values/strings.xml. Is there any examples out there not using this flow? – Nelson.b.austin Jan 09 '20 at 14:00
-
Forgive me, you're correct. The client_id and secret_id associate your app with a particular cognito identity pool. These would need to be stored with your app. If I understand the architecture correctly, these keys allow you to make an OAuth request to cognito to associate an identity from an OAuth provider and an identity in Cognito. After this step, you can proceed in a couple different ways, but usually you'd call assumeRoleWithWebIdentity and get temp creds. These creds have the actual permissions and should not be stored, just renewed as needed. – TopherIsSwell Jan 10 '20 at 21:58