Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restricting request origin for AWS Cognito User Pools javascript api

I'm concerned that the AWS Cognito User Pools Javascript API doesn't seem to care which website requests are coming 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?

like image 883
nakedfanatic Avatar asked Oct 22 '16 01:10

nakedfanatic


People also ask

Which option allows you to assign the user pool to the API in the Amazon API gateway console?

Choose (or create) a method on your API. Choose Method Request. Under Settings, choose the pencil icon next to Authorization. Choose one of the available Amazon Cognito user pool authorizers from the drop-down list.

What is user pool in AWS Cognito?

A user pool is a user directory in Amazon Cognito. With a user pool, your users can sign in to your web or mobile app through Amazon Cognito. Your users can also sign in through social identity providers like Google, Facebook, Amazon, or Apple, and through SAML identity providers.

What is cognitoIdentityId?

cognitoIdentityId as the user Id. This is the Id that a user is assigned through the Identity Pool. However, you cannot use this Id to look up information for this user from the User Pool. This is because to access your Lambda function, your user needs to: Authenticate through your User Pool.


1 Answers

So, 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 and ClientID - 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.com: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 coming 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:

  1. Go into User Pools and set up a pool
  2. Add a cognito idetity pool
  3. Go into Lambda and hook up a function with an API Gateway Trigger Event
  4. 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.

  1. Go to the trigger event from API Gateway
  2. Click on your method and go into the section Integration Request
  3. At the bottom you'll see Body Mapping Templates
  4. Add a new one and put in application/json
  5. You should see the sample template come 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.

like image 85
iSkore Avatar answered Sep 21 '22 14:09

iSkore