Step 1. Add GetPageSpeed extras YUM repository
First, run the following command to add our repository:
sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm
Step 2. Install NGINX and CAPTCHA module
Install latest stable NGINX:
sudo yum -y install nginx
Install the required modules:
sudo yum -y install nginx-module-form-input nginx-module-set-misc nginx-module-captcha
Enable installed modules
Add the following at the top of /etc/nginx/nginx.conf
:
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_set_misc_module.so;
load_module modules/ngx_http_form_input_module.so;
load_module modules/ngx_http_captcha_module.so;
Set up sample captcha configuration
location = /captcha {
captcha;
}
location = /login {
set_form_input $csrf_form _token;
set_unescape_uri $csrf_unescape $csrf_form;
set_form_input $captcha_form captcha;
set_unescape_uri $captcha_unescape $captcha_form;
set_md5 $captcha_md5 "secret${captcha_unescape}${csrf_unescape}";
if ($captcha_md5 != $cookie_captcha) {
# captcha invalid code
}
}
Verify CAPTCHA
Visit example.com/captcha?csrf=test
and observe the captcha image being loaded in the browser.
Refer to the documentation for additional configuration details.
Implementation on a website
You must implement the captcha on your website via HTML code. You can insert simple HTML of the image tag:
<img src="/captcha?csrf=..." />
The csrf
argument value
The csrf
argument is required to prevent cross-site scripting attacks. Your application’s framework must generate a CSRF token.
For example, in Laravel 8, you can get the CSRF token via the csrf_token()
helper function.
Taking Laravel 8, for example, we have the following Blade template:
<form method="POST" action="/profile">
@csrf
<!-- Equivalent to... -->
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>
In our NGINX configuration above, the set_form_input $csrf_form _token;
takes the value of the submitted _token
argument, which contains the CSRF token, and uses it in combination with the validation of captcha input.
How it works
When an image is loaded via /captcha?csrf=...
request, it sends an HTTP cookie to the browser, e.g.:
Captcha=b4727e2bc1905f55d5ef07b83639aa76; Max-Age=300
In our NGINX configuration which is implemented for the login page, we have a check whether captcha was valid:
...
if ($captcha_md5 != $cookie_captcha) {
# captcha invalid code
}
...
In there we can implement various things, e.g. incrementing login count (with some Lua scripting), or simply returning an error page if you don’t tolerate failed captchas at all, e.g.
...
if ($captcha_md5 != $cookie_captcha) {
return 403;
}
...
This allows reducing the load from bots in a more efficient way because, in the case of valid input, the corresponding framework is not being loaded.