
Adding CloudFlare Turnstile CAPTCHAs to CFML Sites
CloudFlare recently released a new CAPTCHA service called Turnstile, which aims to provide a better user experience for CAPTCHA's. At the worst case the user will have to click a checkbox, rather than train a machine learning model solving a puzzle. You don't need to use CloudFlare's CDN / dynamic proxy services on your site to use this service, and it is free to use. Client Side Implementation There are a few different ways to implement the front end side, but at a minimum you would just add these two lines to an existing form: <div class="cf-turnstile" data-sitekey="YOUR-SITE-KEY"></div> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> Make sure you replace YOUR-SITE-KEY with Site Key that CloudFlare provides to you. The JavaScript will automatically insert a hidden input field inside the div named cf-turnstile-response. When the captcha is solved it will also automatically fill value of the hidden field with the captcha response code: <input type="hidden" name="cf-turnstile-response" value="automatically filled and generated"> Server Side Implementation Now your job on the server side is to verify that the value passed in cf-turnstile-response is legit. On the form action page you will need to make a HTTP request to cloudflare with your secret key and the cf-turnstile-response value. Here's a ColdFusion / CFML function I've implemented that takes care of it all: function verifyTurnstileResponse(secret, response, remoteip="") { try { var httpResult = ""; cfhttp(url="https://challenges.cloudflare.com/turnstile/v0/siteverify", method="POST", result="httpResult", timeout=5) { cfhttpparam(name="secret", value=arguments.secret, type="formfield"); cfhttpparam(name="response", value=arguments.response, type="formfield"); if (len(arguments.remoteip)) { cfhttpparam(name="remoteip", value=arguments.remoteip, type="formfield"); } } if (isJSON(httpResult.fileContent)) { return deserializeJSON(httpResult.fileContent); } else { return { "success": false, "error-codes":["response-was-not-json"], "http-result": httpResult}; } } catch (any err) { return { "success": false, "error-codes":["exception"], "exception": err}; } } The function should always return a struct with the boolean key "success", if the HTTP request fails for any reason it will return with a success value of false. Here's how you might use it... var turnstile = verifyTurnstileResponse(secret=server.system.environment.TURNSTILE_SECRET, response=form["cf-turnstile-response"]); if (turnstile.success) { //do it } else { //log / display error } The remoteip argument is optional, so I left it out in my example. I didn't want to default it to cgi.remote_addr because in some proxied environments that wouldn't be the correct IP. I'll probably turn this code into a ColdBox module at some point as well.
From: Pete Freitag's Homepage