reCAPTCHAv3 Explored
I am breaking my own rule temporarily and this is not a static site for the moment. For a proof of value, I am demoing some of the insights you can gain simply by using reCAPTCHAv3.
Suppose I have a form that makes an async CORS request requiring some level of trust. In this example I am invoking an AWS Lambda endpoint that does not trust the users clicking this button. Perhaps they are bots, perhaps not, but with reCAPTCHAv3 all I need to do is load the Google scripts with my site key.
Load the JavaScript.
<script src="https://www.google.com/recaptcha/api.js"></script>
Add some callbacks.
<script>
function privRequest(token) {
console.log(token)
$.get(
"https://zd6em4b0te.execute-api.us-west-2.amazonaws.com/default/mySecretMood",
{ token: token },
(res) =>
$('#test').html(`
<h4>Token</h4>
<code>${token}</code>
<h4>Site inspection result (seen server-side)</h4>
<code>${res.body}</code>
`)
)
}
</script>
Add some attributes to the button element.
<button
class="g-recaptcha button"
data-sitekey="6Le7J-gZAAAAAIFTGsv88nwaRjo6iZOmjb-uiG1p"
data-callback='privRequest'
data-action='submit'>Submit
</button>
The Google docs are pretty straightforward on how to generate the client and server (secret) key pairs.
Once you’ve clicked the button above, you’ll see some interesting stuff from both a client and server perspective. For this demo, I’m simply returning the value of the server-side introspection from my super sensitive endopint that doesn’t want bots.
So what are we achieving here? Firstly , we are automatically geneating a CSRF token to prevent replays. A single click is a single action is a single token.
My Lambda is very simple.
const got = require('got')
exports.handler = async(event, context) => {
console.info(event);
const captchaSecret = [redacted];
const captchaResponse = event.queryStringParameters.token;
const captchaIp = event.requestContext.identity.sourceIp;
const captchaUrl = 'https://google.com/recaptcha/api/siteverify';
const params = {
secret: captchaSecret,
response: captchaResponse,
remoteip: captchaIp
};
const { body } = await got.post(captchaUrl, {
searchParams: params
});
const response = {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'https://wh.itesi.de'
},
body: JSON.stringify({ body }),
};
return response;
};
You can see that all it really does is perform the introspection of the client-side token calling Google’s siteverify
endpoint. Google is automatically assigning my unique client token a trust value in a range of (0.0 - 0.9)
.
Now suppose that I want to action upon such data. My Lambda function could be modified to, for example, alert somebody or return a 403
response (forbidden) if the trust score falls below 0.5
.