Search code examples
amazon-web-servicesamazon-s3aws-api-gatewayamazon-cloudfrontamazon-waf

Custom Origin Header not visible in the API


I have an application where the client is hosted on S3 with a CloudFront distribution. The API is behind an API Gateway with a WAF, and the client makes http requests to the API to fetch and post data.

I want to restrict the access to the API such that it's only available from the client, and it should return an error when someone tries to access the API directly.

The trick is that the API is exposed to a 3rd party, so I cannot use API Gateway authorizers, because they must have direct access.

I set up a Custom Origin Header (My-Secret-Header: 1234567890qwertyuiop) in CloudFront, and I thought that I could create a rule in WAF to allow requests with this header (plus the 3rd party based on other criteria, but that part is working well, and it's not an issue), and block everything else.

The problem is that My-Secret-Header never makes it to the WAF, and it doesn't get added to the http requests originated from the client application.

I also tried to add the custom header with Lambda@Edge, no success. I created heaps of logs in with Lambda@Edge, and the event.Records[0].cf.request.origin.s3.customHeaders shows My-Secret-Header (which is expected).

What is the best way to add a custom header to the client request, so that it would be possible to create a rule in WAF?


Solution

  • I want to restrict the access to the API such that it's only available from the client, and it should return an error when someone tries to access the API directly.

    The short answer is: there is no way to do this. There is no way to tell if a request originates from JavaScript in the browser, a Postman call, a user typing the URL in the address bar, etc.

    Custom Headers in CloudFront are not headers that are added onto API requests that the user makes from the served files. They are headers that CloudFront uses to retrieve the static source that it is serving. In the case that the source is in an S3 bucket, these custom headers are on the request that CloudFront uses to retrieve files from your S3 bucket.

    Once a user has the files that CloudFront serves (HTML, CSS, JavaScript, assets, etc.), CloudFront is no longer a part of the process. Any API calls made on the frontend do not go through CloudFront.

    There are a few very weak ways to do what you are trying to do, but all are easily bypassable and absolutely cannot be used when security is in any way necessary. For instance, you can make an API Key and hard-code it into the application, but it is completely exposed to anyone who can access the page. Same for hard-coded access key ID and secret access key.

    Ultimately what you need is an authentication system, some way to make sure that users are allowed to make the API calls that they are making. I don't know if this fits your use case, but Amazon Cognito is an excellent service that handles user authentication and federation.