AWS WAF Captcha & CloudFront

Siddharth Malani
3 min readNov 16, 2023

--

To implement AWS WAF captcha with a web app setup with S3 based website and API gateway please follow this blog. Before we begin just need to point a few important points around the AWS services used in the example pattern.

So you have a S3 website that holds the static files for React/Angular. You have API gateway setup to services this app. Also you have added AWS WAF (Web Application Firewall) to the solution. And now you want to implement captcha. WAF comes with an in built captcha which is very easy to implement. However there are pitfalls and you just need to be aware of it.

CloudFront

You have CloudFront in front of the S3 bucket website. Also in order to forward calls to say the api, you can use CloudFront behaviours to proxy requests to the api to API Gateway.

So for example lets say you have a website https://example.com -> cloudfront domain -> s3 bucket. Calls made will be to https://example.com/api where your api calls are being made. A rule such as /api* in Cloudfront behaviour can be forwarded to API gateway origin.

WAF Global

WAF Global supports CloudFront. So we add a WAF global attached to the CloudFront.

WAF Regional

WAF regional supports API gateway, ALB and some other services. So add a WAF Regional and attach to API gateway/ALB depending on what you use.

So now all your React JS static files are serviced from S3 via WAF Global and CloudFront. Any calls to API which are made on relative path are routed to API Gateway through WAF regional.

Important

So to enable captcha, add a rule in WAF Global.

Once you have set up the above, when you create the captcha rule you will get a Token and Integration URL. Just follow the following article to implement the captcha in your React or other web application stack.

Some Important Points

API Gateway Access

Add a resource policy to allow access to API only via the account.

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::{{otherAWSAccountID}}:root",
"arn:aws:iam::{{otherAWSAccountID}}:user/{{otherAWSUserName}}",
"arn:aws:iam::{{otherAWSAccountID}}:role/{{otherAWSRoleName}}"
]
},
"Action": "execute-api:Invoke",
"Resource": [
"execute-api:/{{stageNameOrWildcard*}}/{{httpVerbOrWildcard*}}/{{resourcePathOrWildcard*}}"
]
}
]
}

API Keys

The API keys can be hidden when needed in the behaviour config.

Hope this goes smoothly. I got into a twist by enabling the captcha in the WAF Regional thinking that it should be applied on API side as the captcha needed to be invoked when an API call is being made. But since the calls are being proxied via CloudFront all you need to do is move your Captcha Rule into WAF Global and set the rule correctly based on when you want to invoke the captcha.

--

--