I'm concerned that the AWS Cognito User Pools Javascript API doesn't seem to care which website requests are ing from (all you need to use the API are the User Pool ID and Client ID, which would be readily available in my javascript source).
Am I right to be concerned that another site could hijack my user pool, potentially tricking users into signing up to it?
If this is a valid concern, is there any way to prevent this? The pre-authentication Lambda payload doesn't seem to include any request origin data, so I guess that isn't the way to do it.
If it isn't something I need to be concerned about, why is that?
I'm concerned that the AWS Cognito User Pools Javascript API doesn't seem to care which website requests are ing from (all you need to use the API are the User Pool ID and Client ID, which would be readily available in my javascript source).
Am I right to be concerned that another site could hijack my user pool, potentially tricking users into signing up to it?
If this is a valid concern, is there any way to prevent this? The pre-authentication Lambda payload doesn't seem to include any request origin data, so I guess that isn't the way to do it.
If it isn't something I need to be concerned about, why is that?
Share Improve this question edited Jun 25, 2017 at 17:12 iSkore 7,5493 gold badges35 silver badges61 bronze badges asked Oct 22, 2016 at 1:39 nakedfanaticnakedfanatic 3,1982 gold badges30 silver badges34 bronze badges1 Answer
Reset to default 7 +50So, I have contemplated this in great length and decided this:
Yes it's ok to have those digits on your front end.
Of course - for many reasons as follows.
First:
Question:
Am I right to be concerned that another site could hijack my user pool, potentially tricking users into signing up to it?
Response:
If I were to take your
UserPoolID
andClientID
- could I "hijack" to your application?
Answer:
Not exactly...maybe kinda sorta but why...
The level of "tenancy" or "permission" you give to a client is entirely up to you and your IAM Roles. Lets say we don't consider my second and more relavant reason, yet - (origin checks).
If I steal your access keys and misuse your app/brand/whatever, I am simply driving clients to your site. I cannot gain access to your client list, data, logs, records, etc. IF you set your authenticated user permissions to not allow that. Locking down your "Admin Level" permissions to client lists, pool info, data, etc.
Example (added to your Statement
section):
{
"Effect": "Deny",
"Action": [
"cognito-identity:CreateIdentityPool",
"cognito-identity:DeleteIdentityPool",
"cognito-identity:DeleteIdentities",
"cognito-identity:DescribeIdentity",
"cognito-identity:DescribeIdentityPool",
"cognito-identity:GetIdentityPoolRoles",
"cognito-identity:ListIdentities",
"cognito-identity:ListIdentityPools",
"cognito-identity:LookupDeveloperIdentity",
"cognito-identity:MergeDeveloperIdentities",
"cognito-identity:SetIdentityPoolRoles",
"cognito-identity:UnlinkDeveloperIdentity",
"cognito-identity:UpdateIdentityPool"
],
"Resource": [
"arn:aws:cognito-identity:us-east-1:ACCOUNT_DIGITS:identitypool/us-east-1:PoolID_NUMBERS"
]
}
Or simply the opposite:
{
"Effect": "Allow",
"Action": [
"cognito-identity:GetOpenIdTokenForDeveloperIdentity"
],
"Resource": "arn:aws:cognito-identity:us-east-1:ACCOUNT_DIGITS:identitypool/us-east-1:NUMBERS-NUMBERS-PoolID"
}
Only need the "cognito-identity:GetOpenIdTokenForDeveloperIdentity"
part.
Locking down your "User Level" permissions to stuff
Example:
{
"Effect": "Allow",
"Action": [ "s3:PutObject", "s3:GetObject" ],
"Resource": [
"arn:aws:s3:::[bucket]/[folder]/${cognito-identity.amazonaws.:sub}/*"
]
}
As an obvious rule of thumb - only give users permission to what they need. Lock down all the crap you can possibly lock down and use the policy simulator. Conclusion to reason one:
You can lock down all the things that would expose your client base and make it pointless for someone to 'hyjack' your site. Counter argument:
Ya, but what IF
Here is a doc that might help for IAM stuff And some more
Second:
Question:
The pre-authentication Lambda payload doesn't seem to include any request origin data, so I guess that isn't the way to do it.
Response:
Hmm.
Answer:
Yes it does include request origin data - IF one sets it up.
Question:
I'm concerned that the AWS Cognito User Pools Javascript API doesn't seem to care which website requests are ing from
Answer:
For this - you're correct. If you are using static served files with user pools triggers - there is little done to check origin.
So - if you really want to - you can set all this up using API Gateway to Lambda. This will remove direct interaction with User Pools from the client side and put it on the back end.
Preface:
Sets to setup:
- Go into User Pools and set up a pool
- Add a cognito idetity pool
- Go into Lambda and hook up a function with an API Gateway Trigger Event
- put in your code - this is a "login" example:
const
AWS = require( 'aws-sdk' ),
UserPool = new AWS.CognitoIdentityServiceProvider();
exports.handler = ( event, context, callback ) => {
console.log( event );
const params = {
AuthFlow: 'CUSTOM_AUTH',
ClientId: 'numbers',
AuthParameters: {
USERNAME: event.email,
PASSWORD: event.password
}
};
UserPool.initiateAuth( params, ( err, data ) => {
callback( err, data );
} );
};
In the above - yes you can do:
UserPool.initiateAuth( params, callback );
Instead of:
UserPool.initiateAuth( params, ( err, data ) => {
callback( err, data );
} );
But this throws weird errors - there is an issue open on GitHub about it already.
- Go to the trigger event from API Gateway
- Click on your method and go into the section
Integration Request
- At the bottom you'll see
Body Mapping Templates
- Add a new one and put in
application/json
- You should see the sample template e up that follows:
This is Apache Template Velocity Language
- different from the JSONScheme
language used by the other mapping template things:
#set($allParams = $input.params())
{
"body-json" : $input.json('$'),
"params" : {
#foreach($type in $allParams.keySet())
#set($params = $allParams.get($type))
"$type" : {
#foreach($paramName in $params.keySet())
"$paramName" : "$util.escapeJavaScript($params.get($paramName))"
#if($foreach.hasNext),#end
#end
}
#if($foreach.hasNext),#end
#end
},
"stage-variables" : {
#foreach($key in $stageVariables.keySet())
"$key" : "$util.escapeJavaScript($stageVariables.get($key))"
#if($foreach.hasNext),#end
#end
},
"context" : {
"account-id" : "$context.identity.accountId",
"api-id" : "$context.apiId",
"api-key" : "$context.identity.apiKey",
"authorizer-principal-id" : "$context.authorizer.principalId",
"caller" : "$context.identity.caller",
"cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider",
"cognito-authentication-type" : "$context.identity.cognitoAuthenticationType",
"cognito-identity-id" : "$context.identity.cognitoIdentityId",
"cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId",
"http-method" : "$context.httpMethod",
"stage" : "$context.stage",
"source-ip" : "$context.identity.sourceIp",
"user" : "$context.identity.user",
"user-agent" : "$context.identity.userAgent",
"user-arn" : "$context.identity.userArn",
"request-id" : "$context.requestId",
"resource-id" : "$context.resourceId",
"resource-path" : "$context.resourcePath"
}
}
With this, you can get the source-ip
, cognito information, etc.
This method is a secure method for locking down origin. You can either check origin by doing an if
check in Lambda, or a IAM condition - blocking all requests from other origins.