AWS ApiGateway API POST request fails when WAF Captcha is turned on

0

I have setup a AWS ApiGateway rest API. Its a simple API with one endpoint for a POST request. Works without issues.

However when I add my AWS WAF rule for Captcha to the protect the API Gateway I am getting cors errors. If I change the rule from Captcha to just allow no issues.

When I make the same API call from restninja.io with the Captcha token present in the header no issue. Everything works.

To give more background, I am trying the new Application Integration for WAF captcha which lets you render the captcha challenge on your own page instead of it being the page.

// this is how I initialize the Captcha challenge 
AwsWafCaptcha.renderCaptcha(container, {
      apiKey: "ApiKeyHere",
      onSuccess: captchaExampleSuccessFunction,
      onError: captchaExampleErrorFunction,
      dynamicWidth: true, 
      skipTitle: true
    });

// how I retrieve the token before my POST request 
const token = await AwsWafIntegration.getToken();


// this is my API call using the AWS Waf Fetch wrapper 
// the call works without Captcha rule being turned on and all the options being commented out, included it here just to show what I have been trying from the frontend side

const response = await (window as any).AwsWafIntegration.fetch(url, {
    method: "POST",
    // mode: "cors", 
    // cache: "no-cache",
    // credentials: "include",
    // headers: {
    //   "Content-Type": "application/json",
    //   // "X-Aws-Waf-Token": token,
    //   // "Cookie": `aws-waf-token=${token}`
    // },
    body: JSON.stringify(data),
  });

I feel I am missing something super minor, as I mentioned earlier I am able to get it to work with restninja.io but have not been able to figure out what the difference is.

2 Answers
1

AWS WAF can indeed cause CORS errors when it triggers a CAPTCHA check. When a request matches the criteria for a CAPTCHA check, AWS WAF will evaluate the state of the request's token. If the token is valid and unexpired, the request is allowed to proceed to the next rule, similar to a CountAction. However, if the token is missing, invalid, or expired, AWS WAF blocks the request from reaching its intended destination​.

https://docs.aws.amazon.com/waf/latest/APIReference/API_CaptchaAction.html https://docs.aws.amazon.com/waf/latest/developerguide/waf-captcha-and-challenge-actions.html

When AWS WAF blocks a request due to CAPTCHA, it generates a response back to the client which includes the header x-amzn-waf-action with a value of captcha, and the HTTP status code 405 Method Not Allowed. If the request contains an Accept header with a value of text/html, the response includes a CAPTCHA JavaScript page interstitial​.

It's important to note that when AWS WAF responds with a CAPTCHA or Challenge response, it does not include CORS headers. CORS headers are a set of access control headers that tell the client's web browser which domains, HTTP methods, and HTTP headers can be used by JavaScript applications. Without CORS headers, JavaScript applications running in a client browser are not granted access to HTTP headers and are unable to read the x-amzn-waf-action header. As a result, a CORS error can occur when AWS WAF returns a CAPTCHA or Challenge response.

To resolve CORS errors, you need to configure your API Gateway and your backend integrations (such as AWS Lambda) to return the required CORS headers. This can include configuring CORS on the API resource experiencing the error, configuring your REST API integrations to return the required CORS headers, and making sure that the Access-Control-Allow-Origin header includes a list of allowed domains​.

https://repost.aws/knowledge-center/api-gateway-cors-errors

profile picture
EXPERT
answered 10 months ago
  • Here is what I have done in my CDK for API and in the Lambda, I had cors error which I manage to resolve prior to enabling WAF Captcha

    const corsOptions: CorsOptions = {
            allowOrigins: ['*'], 
            allowMethods: ['*'], 
            allowHeaders: ['*'], 
            exposeHeaders: ['*'],
            allowCredentials: true, 
          };
    
        // API Gateway
        new RestApi($this, 'MyApiGatewayBeta', {
            restApiName: 'myBeta',
            defaultCorsPreflightOptions: corsOptions,
        });
    

    and here is my lambda headers

    const getReturnObject = (response: any) => {
      return {
        headers:  {
          "Access-Control-Allow-Headers" : "*",
          "Access-Control-Allow-Origin": "*",
          "Access-Control-Allow-Methods": "*",
          "Access-Control-Expose-Headers": "*",
          "Access-Control-Allow-Credentials": "true"
        },
        ...response
      };
    };
    
0
Accepted Answer

Figured it out, it was due to my WAF Captcha rule, my rule was too generic and included the OPTIONS api, I adjusted the rule to only target my POST api, once I did that the OPTION call succeeded and then when I provided a valid Captcha Token with my POST request it worked .

ryuu
answered 10 months ago
profile picture
EXPERT
reviewed 10 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions