How sensitive is my identity pool id? - javascript

Background
I've been working on a front end javascript application that consumes AWS resources (mostly Lambdas behind API Gateway). The API Gateway resources are protected with IAM, and the app uses most of what Cognito offers accordingly.
This includes an Identity Pool with Unauthenticated Identities enabled, and federation with both a Cognito User Pool and multiple social and custom OIDC providers. Cognito is interacted with solely from our front end javascript code, using Amazon's SDK.
Unauthenticated Identities
The sensitivity of the ID pool id applies to all my use cases, but I'm most curious about the Unauthenticated use case. We've been following what seems to be Amazon's suggested approach: Use Cognito or STS to get IAM keys, and use those keys to access AWS resources. I've even been spreading this gospel.
This is all well and good, but it does require me to expose my identity pool id to the front end. And the identity pool id is the only thing you need to get IAM keys for your Unauthenticated IAM role.
Theoretically, any attacker could grab my identity pool id and start abusing my resources (that are allowed for the Unauth IAM role) using the same Amazon SDKs that I use.
The Question(s)
In a general sense, how sensitive should I consider an identity pool id to be? Is it just A-ok to show this to anybody?
If I decide it is sensitive enough to not expose to the browser, how do I deal with that? Where and how do I hide it and get to it?
In any case, should I "bake in" a way to rotate the id frequently?
Are there (types of) use cases where it's ok to expose the id, and cases where it isn't?
The answer(s) I'm looking for
As noted in the linked answer above, my understanding is that the Unauthenticated Identities thing isn't bulletproof, and only provides a reasonable level of confidence that it's your app on the other end of the line. In other words, while not impossible, it is at least reasonably difficult for someone to abuse your AWS back end using this model.
In addition to the bullet points above, I'd appreciate any critique of this understanding. Am I underselling the security around unauthenticated IAM access to AWS? Overselling it?
Disclaimers
I'll admit this question smells a lot like this one. I'm not asking about hard coding the identity pool id in my application; this is already fetched from a web service. However, it's still completely exposed to the front end, and you can argue that it's actually easier to pull it out of an AJAX response than out of minified code.
I do lock the Unauth role down as tight as I can, and I understand that allowing anonymous access to stuff can only be so secure.

Related

What is the best way to connect two applications using APIS? (An E-commerce and a chatbot)

I have two applications settled up. One is a E-commerce (TrayCommerce) that has itself an Api (Oauth), from which I can get order, clients, products information, etc. The other one is a chatbot (Take Blip).
My goal is to make the chatbot retrieve information from the e-commerce's API so I can send it to final user.
I thought in two ways of doing it:
Hosting a javascript code inside the bot, so I can call the API whenever user requests data. However, I don't know how to implement the authentication flow on this approach and how I would, in the future, set up a system to receive notifications from the API to send information each time it is updated, since I can only host one js file per action.
Creating a NodeJS API, which will be hosted on a third party, and that will return the information I want, in a formatted way, to the chatbot. I don't know if this is over-engineering, because I already have an API from the e-commerce.
I am sorry if it is a dumb question, I am new to web development, but any information would be valuable for me to choose a workflow for this integration.
To be able to answer, the right question to ask yourself is the sensitiveness of the data inside the e-commerce; and the power granted to the generated token in the auth implementation.
Typically, a chatbot (assuming a web one) is a piece of Javascript held in the client (browser). This piece of code is perfectly readable by the user, thus you have to assume the generated token could be used to perform a request that you didn't intended him to perform.
So as a simple answer :
If — and only if — the implemented OAuth mecanism lets you limit the scope of authorization to the customer, then you can make the customer authenticate directly with TrayCommerce and the appropriate scopes (and use his token to perform on the API). Said differently, if typically TrayCommerce lets you register your Chatbot as a "client" (this is an OAuth keyword), and generate Auth journeys with appropriate 3-parties flows, granting only something like "orders:view:self" for customers, it's OK.
If the TrayCommerce API is more like a "management API"; with auth implemented in a way that you (yourself, not the customer) have to authenticate on it; then this auth mecanism is not suitable for your use-case. You then have to make an API like you described, that would act like a proxy to TrayCommerce. With considerations (see below).
In the case of you making a "Proxy API" to TrayCommerce; you are basically hiding the TrayCommerce Authentication on your server-side, and shifting that responsibility from TrayCommerce to yourself. In such a case, you have to implement your own authentication (+ authorization) mecanism on this API, to be able not to expose TrayCommerce data to the world.

Condition based access to amazon lamda results?

Wondering if it's possible to have a webapp upload a file (userid.input.json) to Amazon S3, which triggers a lambda function that reads the file, does some processing, and saves the result as another (userid.output.json).
However userid.output.json should not be immediately accessible to the web application. The webapplication has to complete a Stripe payment and once the payment completes, the web application can access the (userid.output.json) file on amazon s3.
Before I ask how, I figured I'd first ask if this this scenario can be facilitated / architected on AWS?
Approach
Note that this is an update to the question based on more research. It looks like Amazon Cognito will be the perfect tool for signing in users and tying their user credentials to an IAM role that can read and write to S3 buckets.
So once the user is signed in through Amazon Cognito and has the proper credentials then their files can be uploaded to an S3 bucket and processed by a lambda. The result is then written to the same bucket.
Now earlier I suggested writing to a sealed bucket and having a Stripe webhook trigger moving the result from the sealed bucket to an accessible bucket. But it seems this is necessary, per the indication in the answer provided by #Snickers3192.
Once the stripe payment completes the webapp can set a boolean that is used to control access to the output and that completes the cycle?
Part of the rational for having a hidden bucket was that someone might pull the credentials out of the browser and execute them in a different script. I assume this is impossible (Famous last words :) ), but just in case I wrote a follow up question here.
In other words the credentials that are pulled into the client post signin with Amazon Cognito cannot be used to executed scripts outside of the application context?
Approach Part 2
Per my follow up questions it does not appear that relying on state within the webapp for making security decisions is good enough, as someone can probably figure out a way to get the token authentication token and manipulate the applications API directly using a client other than the core app.
So now I'm thinking about it like this:
1) Write the result to the sealed bucket (Processing Lambda)
2) Have the Stripe webhook update the users a transaction record in the users profile indicating payment paid = true (Stripe Lambda)
3) Create another lambda that has access rights to the sealed bucket but will return results only if paid=true. (Access Result Lambda)
So since Stripe is tied to an IAM user that is allowed to update the Application user profile and set paid=true and the sealed bucket can only be accessed by lambda that first checks if paid=true before returning the result, I believe that should guarantee security.
If anyone has a simpler approach please let me know.
This really is more a question of where you want to put the security, which in AWS there are many options, in your application logic which could mean:
Lambda/Webapp
S3 policies
IAM roles/groups
These decisions are usually dictated by where your identity store is kept, and also if you want to keep the notion of AWS users VS. users of your app. My preference is to keep these two pools separate, in that security logic like this is kept in the webapp/lambda and AWS security only deals with what rights developers have to the environment as well as what rights applications themselves have.
This means the webapp can always access the input and output buckets, but it keeps a record in a database somewhere (or makes use of your payment system API) who has paid and who hasn't paid and uses that information to deny or grant access to users. IMO this is a more modular design, and it enables you to lock down your AWS account better and is more clear to developers where security is located. In addition if you do go with IAM/S3 it will be more difficult to run and debug locally.
EDIT: After all your comments and additional security concerns you may also want to consider emailing a short lived URL link to the processed file, so that a user needs both email access as well as knowing their credentials to the application. This will mean even if your access token is stolen at the browser level, without the email access a hacker still can't get the processed file. If you want to be EXTREME SECURITY CORE, have the link that not only is authentication required, but also MFA so that they need to enter in a code which is constantly refreshing as you should have setup for your AWS account when you login.
I'm by no means a security expert but just follow best practices and do your due diligence and you will meet security expectations.

Securing JS client-side SDKs

I'm working on a React-Redux web-app which integrates with AWS Cognito for user authentication/data storage and with the Shopify API so users can buy items through our site.
With both SDKs (Cognito, Shopify), I've run into an issue: Their core functionality attaches data behind the scenes to localStorage, requiring both SDKs to be run client-side.
But running this code entirely client-side means that the API tokens which both APIs require are completely insecure, such that someone could just grab them from my bundle and then authenticate/fill a cart/see inventory/whatever from anywhere (right?).
I wrote issues on both repos to point this out. Here's the more recent one, on Shopify. I've looked at similar questions on SO, but nothing I found addresses these custom SDKs/ingrained localStorage usage directly, and I'm starting to wonder if I'm missing/misunderstanding something about client-side security, so I figured I should just ask people who know more about this.
What I'm interested in is whether, abstractly, there's a good way to secure a client-side SDK like this. Some thoughts:
Originally, I tried to proxy all requests through the server, but then the localStorage functionality didn't work, and I had to fake it out post-request and add a whole bunch of code that the SDK is designed to take care of. This proved prohibitively difficult/messy, especially with Cognito.
I'm also considering creating a server-side endpoint that simply returns the credentials and blocks requests from outside the domain. In that case, the creds wouldn't be in the bundle, but wouldn't they be eventually scannable by someone on the site once that request for credentials has been made?
Is the idea that these secret keys don't actually need to be secure, because adding to a Shopify cart or registering a user with an application don't need to be secure actions? I'm just worried that I obviously don't know the full scope of actions that a user could take with these credentials, and it feels like an obvious best practice to keep them secret.
Thanks!
Can't you just put the keys and such in a .env file? This way nobody can see what keys you've got stored in there. You can then access your keys through process.env.YOUR_VAR
For Cognito you could store stuff like user pool id, app client id, identity pool id in a .env file.
NPM package for dotenv can be found here: NPM dotenv
Furthermore, what supersecret stuff are you currently storing that you're worried about? By "API tokens", do you mean the OpenId token which you get after authenticating to Cognito?
I can respond to the Cognito portion for this. Your AWS Secret Key and Access Key are not stored in the client. For your React.js app, you only need the Cognito User Pool Id and the App Client Id in your app. Those are the only keys that are exposed to the user.
I cover this in detail in a comprehensive tutorial here - http://serverless-stack.com/chapters/login-with-aws-cognito.html

How to make a web API private

I have an API that I would like to restrict access to. I can provide access keys and check them with each request, but I'm not sure how far this is really going to go.
The API is used by applications, but it is also used by a web app which someone can just view the source of. If they did, they would have the key and could easily make API calls.
Is there a more reliable way to secure access? I'm not sure what the standard practice here is.
Edit: After thinking about it, I could use a two-prong approach. The web app can use POST with CSRF, and applications can use API keys. Any other ideas, or is this a generally accepted solution? (Note, this still wouldn't work for third-party web apps.)
Your API is never private since it's used by a web app which I am assuming is available to the general public. If this is the case, there really is no impetus to secure it since anyone and everyone would have access to the API.
If on the other hand, this web app is only available to registered users, you can use a token system to check for authorization. When the user successfully logs in, you pass back a token (usually something 20 to 30 characters long). Every API request would require a valid token. Tokens can be set to expire automatically (using a database job) X hours after creation if your application requires higher security thresholds. If security isn't a big issue, they can be renewed automatically every time a request is made.
This is essentially a two tiered approach. Temporary tokens are generated for users to directly connect to your API so that permanent credentials are never sent to the client. Predefined keys are given to third party developers who build applications on top of your API and have their own back-end.
If it's your API you can simply do this.
1) Insert the following code into your API file(s)
$authToken = "APItoken"; //variables
if( !isset($_REQUEST["authToken"]) || $_REQUEST["authToken"] != $authToken )
die("Need auth token");
2) You will now need to GET/POST/PUT the URL like this:
http://www.yoursite.com/api1.php?authToken=APItoken&nextParam=&paramAfterThat=
If this helped please mark it as the answer
EDIT:
Nevermind, read it wrong. Updating answer in a few minutes.

CouchDB and Cloudant Security

We have used CouchDB in production, mainly building apps in controlled environments. Most times, we use a middle-ware library to make direct calls onto couchdb/cloudant, hence avoiding direct (Front-End JavaScript calls direct onto CouchDB/Cloudant).
For security reasons, it is obvious that for an authenticated CouchDB database: http://{username}:{password}#IPAddress:Port/DB OR for cloudant: https://{username}:{password}#username.cloudant.com/DB ,
If the call is directly made from JavaScript, Developer tools in the browsers today enable a person to realise this call and hence has access to your database entirely.
Attachments are usually painful when handled in the middle-ware. It is advantageous to make cloudant handle the caching and serving of the attachments directly to the front end hence relieving our middle ware from that. However, on the web and with a huge audience, making direct calls to our cloudant environment is tricky.
We started out by first of all having a separate cloudant account for all attachments such that, an inquisitive boy will not tamper with the actual meta-data or information of our users. So, the only cloudant account they can have access to is that of the attachments since we are making direct JavaScript calls to our database.
Question: How do we find a way in which we hide the Username and Password of our cloudant environment thereby allowing us to securely make direct JavaScript calls onto cloudant ? Our infrastructure is entirely in the cloud, so we don't have proxies and stuff to work with. We have heard of Url shortening services, CDNs e.t.c. but, we have not come up with a really conclusive solution.
Try using the _session endpoint. This will set up cookie authentication.
How do we find a way in which we hide the Username and Password of our cloudant environment thereby allowing us to securely make direct JavaScript calls onto cloudant ?
As far as I know you can't do that without using a middleware or some kind of proxy. But that does not mean we are completely defenceless. couchdb gives us some spears to poke inquisitive boy :)
So a good thing that you have done is to make the attachments database seperate. You don't mention in your question if you are using couchdb authorization scheme so I going to assume that you are not. So the first step is to create a user in couchdb _users database and then assign it as a member in the attachments database. More details here and here.
After this step you should have a member on attachments database. The reason we want a member and not an admin is that members do not have permissions to write or read design documents.
It's a start but it's not enough since a member can still read via _all_docs and that is a dos attack right there. So the problem we face now is that we do this at the moment
https://{username}:{password}#username.cloudant.com/DB
A very good move would be to change it to
https://{username}:{password}#someurl.com/
What's the difference between these two? Well it hides the location of your database and makes accessing built in methods harder. This can be accomplished with the help of vhosts configuration and some rewrite rules. Some very good stuff is on Caolan's blog too
With this in place you have got two things going for you.
The stalker inquisitive boy will be clueless where the calls go to.
There will be no way he can get the contents of unknown documents by making direct calls. He can only access your database through the rules that you set.
Still not 100% secure but it's okay as far as read level security goes. Hope this helps.

Categories

Resources