AWS API authorizer include body - amazon-web-services

Is there a way to validate request in API Gateway based on its body? I need to calculate SHA1 hash of the body to validate the sender - Facebook messenger events... Is there a workaround for it?

ApiGateway does not support passing complete body to custom authorizer.
One option is to have two level of authentication - first just based on header/query parameter ( which api gateway support ) and enough to detect spoof senders. Second can be SHA1 hash based on complete body which you can implement in your backend

Related

Is there any way to validate path parameters in AWS API Gateway?

I'm using AWS API Gateway to create an api.
I have the following path for an API: /users/{id}
Is there a way to validate the existence of id in the API request made and maybe its type in API Gateway before it reaches the Lambda integration? I understand API Gateway supports validating request body, query params and headers, but I can't see any option for path parameters, does API Gateway not support that?
I'm going through the documentation and I can't seem to find something clear on that.
API Gateway can check if a path parameter exists or not. It can check if path includes any "id", but it cannot for example check what is it’s regex pattern. Such validation should be made on a client side. Either the API Gateway path follows the defined pattern, in which case it can route you to an appropriate resource, or not. It can however ensure that request parameters are present and non-blank.
The AWS documentation states that API Gateway can perform the basic validation:
API Gateway can perform the basic validation. This enables you, the
API developer, to focus on app-specific deep validation in the
backend. For the basic validation, API Gateway verifies either or both of the following conditions:
The required request parameters in the URI, query string, and headers of an incoming request are included and non-blank.
The applicable request payload adheres to the configured JSON schema request model of the method.
To enable basic validation, you specify validation rules in a request validator, add the validator to the API's map of request validators, and assign the validator to individual API methods.
Note that comparison with JSON schema request model refers to the request payload, and not to request parameters. In the documentation you can find guidance on how to enable request validation in API Gateway:
by importing OpenAPI
definition
using the API Gateway REST
API
using AWS
console
Also, follow this blog post which explains how to set up request parameters validation. Mind however, that the basic validation ensures that the request parameters are present and non-blank. More advanced validation, like checking regex pattern or type, is not possible to my knowledge.

Is AWS usage plan in effect even without API-key as authorization mechanism?

When using API-keys and usage plans for AWS API-gateway - is usage plan used even though the authorization method is not using API-keys (I would still pass x-api-key http header to the API)?
I ran into the same question, but I did not find the answer so I did some testing myself. This is what I found: Even if a method is not API Key required, any request sent to the method with API key in header will subject to the usage plan which is associated API key.
The test I did is:
create method A and set requireApiKey to false
set the rate and burst throttling values to 0 for a method A under a usage plan
associate an APIKey K with the usage plan
sent request through PostMan to method A with including K in header, resulted "Too Many Requests" error
sent request through PostMan to method A without including K in header, request succeeded.

Serverless AWS - is it worth using custom authorizers (as a lambda)?

Hey I am getting started with the serverless framework, apigateway, lambdas and authorizers.
Here my questions:
In order to verify a proper JWT token (which seems nowadays the best solution for serverless authentication), I would need a client id. Since the authorizer lambda is not capable(?) of reaching any other parameters of the request into the lambda except for the token itself, this is a difficult task to do. How can I achieve this?
Since with every authenticated call, an additional lambda is called, my costs are doubled?! May be I am misunderstanding something here, but it seems to me like implementing a method for verifying my token without using the authorizer is cheaper and I don't need to implement the authorizer lambda itself.
The whole point of OAuth2 is that at the point of authorization you don't care who the bearer presenting you with a token is or which client they are using (web app, Postman, etc.), only that the token is valid for whatever the token bearer is trying to do. You trust that the authentication has happened because the token issuer has done the authentication.
When you talk about the aud(audience) (from comments) in JWTs, which may or may not be included dependent on the JWT issuer, this is intended to reflect the service or services that the JWT is valid for.
This could for example have a value of 'myAPIName' or 'myAPIName/test' or even ['myAPIName/test1', 'myAPIName/test2'].
If you need to validate an individual aud claim you have two choices, you can either have different Lambdas authorizing different api routes and methods with hardcoded aud variables or you can get the name of the api being called and map it back to something that would match an aud claim.
For example the method arn for the incoming request can be found in event.methodArn. This looks like arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/ potentially with [{resource}/[{child-resources}]] dependent on your implementation. With a bit of string manipulation, you could map this back to the format of an audience claim (whatever that looks like for you).
If you would rather work an api name instead of an api name you can use the apigateway.getrestapi method for whatever sdk you are using. Documentation on this method for the JavaScript sdk can be found here.
The JWT may have a sub(subject claim), again dependent on implementation of the JWT issuer, this could relate to any of your users (or at least the users the JWT issuer knows about). Validating this beyond checking the signature of the JWT is pointless. The best you could do is check if that user exists and only if you have access to the same user database that the JWT issuer does. Although this can be used to ensure that UserA only has access to UserA's data. Again, you are trusting that the fact a bearer has a token is proof that they have authenticated (proved who they are).
I hope that answers part one of your question.
In regards to part 2, the advantage of using a Lambda Authorizer over doing the authorization in the target Lambda is caching.
So envisage I have a token valid for one hour and I call your API once every second for 30 minutes (1,800 calls). You have a Lambda authorizer with a response cache time of 10 minutes. That means you check the JWT 3 times for 1800 api calls.
But if you do the validation of that token in your target Lambda, you are doing that processing 1,800 times.
There is authentication with AWS Cognito which will allow you to use authentication outside your application and still being able to let your application divide the users into subgroups based on custom roles or similar.
If for some reason you cannot use AWS Cognito (Why not?) there is both the possibility of custom authentication (the same for each function with SLS) or even authenticating with custom code inside each lambda function.
I would recommend to use Cognito, and only custom if you know you need it.

Use ApiGateway Authorizer to Validate Github Payload Signature (X-Hub-Signature)

I am currently working on a simple api to receive Github event payloads, and I want to validate that they are coming from the correct source. With this I am working to use the hmac signature in the requests header (generated by github using a secret provided by me). To validate the signature, the ApiGateway authorizer requires the signature (X-Hub-Signature), the secret used to generate the signature, and the body of the message. As far as I can tell, Api Gateway does not allow you to pass the body to an ApiGateway Authorizer. Does anyone know a way around this that does not require additional proxy lambdas and s3?
*Note: The requester is the Github Webhook service (not able to add body to header)
Basic ApiGateway Auth Docs:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html
Here is how you do it.
Pass your content to Authorization header of your incoming request, It will get delivered to your custom Authorizer.
Grab the contents of the from the below attribute,
event.authorizationToken
where event is one of the parameters (1st) passed to lambda,
I currently encrypt and add all the info to that header and gets delivered to the Custom Authorizer lambda.
You can also access additional parameters as below in your custom Authorizer lambda:
var headers = event.headers;
var queryStringParameters = event.queryStringParameters;
var pathParameters = event.pathParameters;
var stageVariables = event.stageVariables;
var requestContext = event.requestContext;
Hope it helps.

When using Amazon API Gateway, how do I get the API key used in the request from a Django backend?

Pretty self explanatory title. I'm using API Gateway in AWS, requiring an API key to access a backend written in Django (not using lambda). I need to know how to access the API key used in the request to keep track of who did what at the app level.
You can use mapping templates and get the API Key from the $context variable, it’s the apiKey property inside the identity object: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference
Create a mapping template for your requests and include the property in it. For example, if you wanted to include the entire request body + the API Key you would do this:
{
"body": $input.json('$'),
"apiKey": "$context.identity.apiKey"
}
Depending on how your backend application is built, you could send the API key to your application in a HTTP parameter (path, query string, or header) or in the request body. Please have a read through the docs on how to move data between the two systems.
Thanks,
Ryan
Here is how I finally made it work. At the top or bottom of the template, include this line.
#set($context.requestOverride.header.x-api-key = $context.identity.apiKey)
When your backend receives this request, the api key will be in the header x-api-key.
Here is a basic mapping template that just forwards the (json) body and the header.
$input.json("$")
#set($context.requestOverride.header.x-api-key = $context.identity.apiKey)
API Gateway uses the X-API-Key header, so I like for my backend to also use that. That way I can use the same testing commands with only the URL being different.