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. (NOTE: this video is for an earlier version of lab that used a more complicated but more flexible approach on the client side. The instructions below are for a much simpler client side implementation but will not match the video. The backend material is pretty much the same and has not changed and should match the video).
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”:
Add an id
attribute to the form element as follows:
Rewrite the markup for the “Signup” but as follows with your actual reCAPTCHA site key:
In public/form-validation.js
, add the following code at the very top of the file – completely outside the large anonymous function:
Pass the reCAPTCHA token to the backend by including it in the call to the signups.create()
method invocation:
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:
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 submitting 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
, rewrite the signups.create()
method invocation with a then()
and catch()
method invocations as follows to handle the successful and error cases:
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.