Simple CAPTCHA
Image
To protect your forms from bots, you can require users to fill out a Simple Captcha text as seen on a dynamically created image.
Configuration
You might want to change how the Captcha looks. This can be done with the captcha.set
config option.
<?php
return [
'bnomei.klub.captcha.set' => function () {
// https://github.com/S1SYPHOS/php-simple-captcha
$builder = new \SimpleCaptcha\Builder;
$builder->bgColor = '#FFFFFF';
$builder->lineColor = '#FFFFFF';
$builder->textColor = '#000000';
$builder->applyEffects = false;
$builder->build();
kirby()->session()->set('captcha', $builder->phrase);
return [
'captcha' => $builder->inline(),
];
},
// other options...
];
Securing Forms
The plugin does not provide a snippet to render the image. However, the following example shows how to use Alpine.js to render the image dynamically, allowing for manual refreshes.
<form action="<?= site()->url() ?>/klub/login" method="POST">
<div x-data="{
captcha: undefined,
refresh() {
fetch('<?= site()->url() ?>/klub/captcha')
.then(response => response.json())
.then(data => {
this.captcha = data.captcha;
})
}
}" x-init="refresh()">
<label>
<span>Captcha: </span>
<input name="captcha" type="text" value=""
required pattern="[a-zA-Z0-9]{5}">
</label>
<figure>
<img :src="captcha" width="150" height="40"/>
</figure>
<button x-on:click="refresh()" type="button">Refresh</button>
</div>
<input type="email" name="email" placeholder="Email" required
value="<?= get('email') ?>">
<input type="hidden" name="redirect" value="<?= page('account')->url() ?>">
<input type="hidden" name="token" value="<?= csrf() ?>">
<button type="submit">Login</button>
</form>
Behind the Scenes
The endpoints intended for public use, which are most likely targeted by bots (login, register/signup, magic-link), are preconfigured with a check for the Simple Captcha.
If posted with the form, the klub()->captcha()
-helper will query the current request for the captcha
and check if the form is legit or not.
Even if you use Captcha, you should keep the csrf
-check as an additional layer of security.
On success the form will continue as intended. If not, it will yield a 401
HTTP status code.