Open joknoxy opened 1 year ago
Hello, @joknoxy and thank you for opening this issue. We've marked this as a feature request and will review this with the team internally. This may be something that requires additional partnership with the Cognito team, but I'll double check on that and provide updates as they come.
Doesn't look like there's a limitation from the Cognito side, we'll just need to implement support on the library side at this point for the new WAF feature.
Has anybody found not-too-tedious to implement workaround here?
Also, I am not quite sure that setting aws-waf-token
to AWS cognito is the right thing? At least I cannot get successful result with curl.
I do render CAPTCHA and solve it and receive a valid token and then copy the request as cURL from browser, inject aws-waf-token
Header and it's still demanding captcha:
curl 'https://cognito-idp.eu-central-1.amazonaws.com/' -X POST \
-H 'User-Agent: some_nonsense' \
-H 'Accept: */*' \
-H 'Accept-Language: en-US,en;q=0.5' \
-H 'Accept-Encoding: gzip, deflate, br' \
-H 'Referer: $MY_DOMAIN' \
-H 'content-type: application/x-amz-json-1.1' \
-H 'x-amz-target: AWSCognitoIdentityProviderService.SignUp' \
-H 'cache-control: no-store, no-cache' \
-H 'x-amz-user-agent: aws-amplify/6.0.13 auth/1 framework/1' \
-H 'Origin: ${MY_ORIGIN}' \
-H 'DNT: 1' -H 'Connection: keep-alive' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Site: cross-site' \
-H 'Sec-GPC: 1' \
-H 'Pragma: no-cache' \
-H 'TE: trailers' \
-H 'aws-waf-token: ${TOKEN}' \ // <- This is the token I receive in browser after successfully solving the challenge
--data-raw '{"Username":"bot","Password":"botpassword","UserAttributes":[{"Name":"email","Value":"botemail@botdomain"}],"ClientId":"..."}'
{"__type":"ForbiddenException","message":"Request not allowed due to WAF captcha."}%
@joknoxy are you certain that the aws-waf-token
header is the right thing? I get it that's what one uses with CloudFront and ALB, but I am not quite sure that works the same way here.. well at least I can't make curl request, identical to what the browser produces but with the aws-waf-token
header injected, work?
I also wrapped simulated SignUp function logic there to wrap it with another JS Wrapper as described in AWS Documentation here like so:
in index.html
:
<script type="text/javascript"
src="${path copied from app waf integration}/challenge.js" defer></script>
declare global {
interface Window {
AwsWafIntegration: {
fetch: (url: string, options: { method: string; headers: Record<string, string>, body: Object }) => Promise<any>;
}
}
}
export async function signUpCustom(input: SignUpInput): Promise<SignUpOutput> {
const endpoint = 'https://cognito-idp.eu-central-1.amazonaws.com/';
const headers = {
'Content-Type': 'application/x-amz-json-1.1',
'X-Amz-Target': 'AWSCognitoIdentityProviderService.SignUp',
'Accept': 'application/json, text/plain, */*',
};
const body = {
ClientId: '',
Username: input.username,
Password: input.password,
UserAttributes: Object.entries(input.options?.userAttributes ?? {}).map(([Name, Value]) => ({ Name, Value })),
ValidationData: input.options?.validationData,
};
const login_response = await window.AwsWafIntegration.fetch(endpoint, {
method: 'POST',
headers,
body: JSON.stringify(body)
});
if (login_response.ok) {
const data = await login_response.json();
const { UserConfirmed, UserSub, CodeDeliveryDetails } = data;
return {
userConfirmed: UserConfirmed,
userSub: UserSub,
codeDeliveryDetails: CodeDeliveryDetails ? {
Destination: CodeDeliveryDetails.Destination,
DeliveryMedium: CodeDeliveryDetails.DeliveryMedium,
AttributeName: CodeDeliveryDetails.AttributeName,
} : undefined,
};
} else {
const errorData = await login_response.json();
console.error("Error response data:", errorData);
throw errorData
}
}
And what I observe is that now it injects x-aws-waf-token
header, but still doesn't work:
POST / HTTP/2
Host: cognito-idp.eu-central-1.amazonaws.com
User-Agent: asdasdasdasddas
Accept: application/json, text/plain, */*
Content-Type: application/x-amz-json-1.1
X-Amz-Target: AWSCognitoIdentityProviderService.SignUp
x-aws-waf-token: // <- FRESHLY OBTAINED WAF VOUCHER
Content-Length: 159
DNT: 1
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Sec-GPC: 1
...
other headers
So, WAF doesn't seem to be persuaded even when it's native App integration Javascript library is used?
Oh ok, the code from previous example actually works ā ā ā ā , I had misconfiguration on WAF side.
@cwomack Any update here? We'd like to use AWS WAF Captchas with the amplify library as well.
Is this related to a new or existing framework?
Angular, React
Is this related to a new or existing API?
Authentication
Is this related to another service?
AWS WAF Intelligent threat javascript integrations
Describe the feature you'd like to request
In order for customers using Amplify client JS frameworks to be able to use the AWS WAF intelligent threat managed rulegroups (AWSManagedRulesACFPRuleSet, AWSManagedRulesATPRuleSet, AWSManagedRulesBotControlRuleSet) to protect Cognito endpoints from malicious Bots, the client needs to send an 'aws-waf-token' header with Amplify 'Auth' requests.
The AWS WAF intelligent threat managed rule groups provide operations for running silent challenges against the user's browser, and for handling the AWS WAF tokens that provide proof of successful challenge and CAPTCHA responses.
POST requests that match AWS WAF rules configured with a CAPTCHA or Challenge action are blocked unless they contain a header (or cookie) named 'aws-waf-token' with an encrypted value that indicates whether Challenge/CAPTCHA has successfully previously been completed. The value of the header is contained in a global variable called 'currentToken' and the way it's used by the WAF provided JS can be seen here in challenge.js - we need Amplify Auth to imitate the behavior in 'challenge.js' if the 'currentToken' variable exists.
Please see the following for more information - https://docs.aws.amazon.com/waf/latest/developerguide/waf-javascript-api.html
Describe the solution you'd like
We need Amplify Auth to emulate the behavior in challenge.js and send header 'aws-waf-token' with Auth requests if the 'currentToken' variable exists.
Describe alternatives you've considered
None
Additional context
No response
Is this something that you'd be interested in working on?