Learning Outcomes
- explain the role of CAPTCHAs in securing web applications
- secure a web application using CAPTCHAs
- utilize a 3rd party service in a web application backend
Resources
- Why CAPTCHAs have gotten so difficult
- reCAPTCHA
- axios: Promise based http client for the browser and Node.js
- Query String Node.js Module
- slides
Lab
Video walk through of this lab.
You can start with your own completed REST assignment, or if there are problems with that, you can use the https://gitlab.com/langarabrian/rest2-final
project. If you use that one, be sure to fork, remove the fork relationship and make private.
Set the MONGODBURI
environment variable as per previous exercises.
Install the dependencies and run in dev mode:
1
2
3
cd rest2-final
npm install
PORT=8080 npm run dev
Verify that the application is running in the web preview.
In a new terminal tab, try this (remove the spaces around “localhost” first):
1
2
3
curl -d '{"firstName":"Bob", "lastName":"Smith", "email":"[email protected]", "country":"USA", "province":"WA", "postalCode":"12345"}' \
-H "Content-Type: application/json" \
-X POST http:// localhost :8080/signups
Refresh your app in the web preview tab and confirm that the new record appears in the table of signups. This means our app is vulnerable to bots that could create 1,000,000s of signups without any human interactions. In the next section we will add a CAPTCHA to discourage bots.
Configure reCAPTCHA Service
Go to the Google reCAPTCHA Admin Console.
Type in a label, like “Signup App”.
For “reCAPTCHA Type”, choose “reCAPTCHA v3”.
For “Domains”, enter the domain from your web preview (which would be something like 8080-dot-3969277-dot-devshell.appspot.com
)
Accept the reCAPTCHA Terms of Service.
Click on the “SUBMIT” button.
Record the “Site” and “Secret” keys.
Configure reCAPTCHA in the Frontend
In public/index.html
, add the following just before “form-validation.js” (replacing YOUR_SITE_KEY
with your actual site key):
In public/form-validation.js
, wrap all of the code inside the “load” event as follows. This ensures the reCAPTCHA API is loaded and initialized before we attempt to use any of its functions:
Replace this code block:
with this (replacing YOUR_SITE_KEY
with your acutal site key). This guards the action we want to make sure is completed by a human and not a bot:
Back in the terminal tab where the app is running, type Ctrl-C to stop the Node app temporarily.
Configure reCAPTCHA in the Application Backend
We are going to create a hook function to be called before a new signup is created to validate the reCAPTCHA:
Answer the questions as follows:
1
2
3
4
What is the name of the hook? process-signup
What kind of hook should it be? before
What service should this hook be for? signups
What methods should the hook be for? create
In the newly generated file, src/hooks/process-signup.ts
, add the following imports to bring in modules that we will need to interact with the reCAPTCHA verification service:
The generated hook function does nothing by default. It takes a single parameter, context
, which contains information about the incoming service request and returns it unmodified, without performing any additional actions:
Replace the body of the hook function with the following code block (using your actual secret key):
Set the RECAPTCHA_SECRET
environment variable as follows (using your actual secret):
1
export RECAPTCHA_SECRET=your-actual-secret-here
Re-start the backend. Try subitting the form. Note your score in the backend terminal window. Play around with the response.data.score
threshold to get something acceptable.
Right now there is nothing in the frontend UI to indicate that the user has failed the reCAPTCHA. If you look in the web console in the browser, you can see the thrown exception. Let’s add a block in the HTML that is normally hidden. We will reveal it when we detect the exception. In the public/index.html
file, add the following just above the “Signup” button:
Handle reCAPTCHA Fails Gracefully in the Frontend
In public/form-validation.js
, wrap the the call to signups service create methond in a try/catch block as follows:
Assignment
- Complete the Feathers JS Tutorial in The Feathers guide with the following modifications:
- complete the TypeScript version
- instead of the NeDB datastore, use the Mongoose driver instead
- Incorporate reCAPTCHA v3 into the tutorial so that a new account is only registered if the score is above 0.7.