Prevent spam with contact form

Hi,

I have a form with modelless forms and receive spam and I am working on prevent this spam.

I have made the following:

Contactcontroller

<?php
namespace App\Controller;

use App\Controller\AppController;
use App\Form\ContactForm;
use Cake\Core\Configure;

class ContactController extends AppController
{
    
    public function initialize()
    {
        parent::initialize();
        $this->Auth->allow(['index']);
    } 
    
    public function index()
    {
        $contact = new ContactForm();
        if ($this->request->is('post')) {
            if ($contact->execute($this->request->getData())) {
                $this->Flash->success('We will get back to you soon.');
                $this->redirect($this->referer());
            } else {
                $this->Flash->error('There was a problem submitting your form.');
            }
        }
        $this->set('contact', $contact);
        $this->set('recaptcha', Configure::read('Users.reCaptcha.key'));
    }
}
?>

Then contactform.php

<?php 
namespace App\Form;

use Cake\Form\Form;
use Cake\Form\Schema;
use Cake\Mailer\Email;
use Cake\Validation\Validator;
use CakeDC\Users\Controller\Traits\ReCaptchaTrait;

class ContactForm extends Form
{
    use ReCaptchaTrait;
    
    protected function _buildSchema(Schema $schema)
    {
        return $schema->addField('name', 'string')
        ->addField('email', ['type' => 'string'])
        ->addField('body', ['type' => 'text']);
    }
    
    protected function _buildValidator(Validator $validator)
    
    {
         
        $validator->add('name', 'length', [
            'rule' => ['minLength', 10],
            'message' => 'A name is required'
        ])->add('email', 'format', [
            'rule' => 'email',
            'message' => 'A valid email address is required',
        ])->add('body', 'length', [
            'rule' => ['minlength', 20], 
            'message' => 'Message can not be empty'
        ])->add('g-recaptcha-response', 'custom', [
            'rule' => function ($value, $context) {
                if (!$value) {
                    return false;
                }
                if (!$this->validateReCaptcha($value,env('REMOTE_ADDR'))){
                    return false;
                }
                return true;
            },
                'message' => 'Need to use the recaptcha'
        ]);
        
        return $validator;
    }
    
    protected function _execute(array $data)
    {
        $email = new Email('default');
        $email->setFrom(['sales@website.com' => 'My Site'])
        ->setTo('sales@website.com')
        ->setSubject('Website')
        ->send('Ip: '.env('REMOTE_ADDR').', Name: '.$data['name'].', Email: '.$data['email'].' Message: '. $data['body']);
        return true;
    }
}
?>

I believe someone is submitting the form without going through the validation. Posting it directly? Am I doing something wrong here. I basicly used the Cakedc/Users RecaptchaTrait

This should just work fine as far as I can tell.
Are you sure somebody didn’t just get your email from somewhere else?

It was coming through the website. I will check if it still persists.

The form works when I use it through a browser, but somehow I was still receiving spam.

hm… odd… Maybe the spammer has some human clicking on the captcha?

I’ve had excellent success blocking spam simply by including a hidden “website” input in the form. Bots can’t tell it’s hidden, and eagerly fill it in, but browsers don’t show it so humans don’t provide any data there. If you get a form with that field set, you know it’s spam.

This will be my next step if it continues. Seems to have stopped for now.

Check the logs of the webserver or ask your provider to do so - typically the client software is being logged so you can at least identify wether the input comes from a browser or some kind of script.

Also, you can try to limit the number of requests to that action on an IP basis (either in your webserver or via cakephp) or use geoIP blocking mechanisms if the spam originates in specific countries…

Hope this helps…

Zuluru has sugested something you should look into which is the CSRF, which creates a session token and add it into your website as a hidden field which cake will validate once the post request has been made.

https://book.cakephp.org/3.0/en/controllers/components/csrf.html

let me know if this help and happy coding

I had disabled the security mod because had some problems with unlockfields. Now it’s working good.

Please do note that CSRF is not much against spam, it does protect a bit against malicious websites.
A somewhat not shitty bot will store the cookies then send them in their own requests.
anti-CSRF is made to protect people from sites trying to forge requests (eg. malicious.com trying to send 200 euro from your PayPal to theirs by forging a request using - for example - AJAX) since a properly implemented CSRF token can only be used on the specific domain of a request (unless you have a vulnerability in your browser, in which case, you have a lot more to worry about).
If you take a look at your cookies in your browser (on a cakephp app), you should see a crsfToken cookie in your browser that’s only usable on that specific domain (in the example below this domain is testing.finlaydag33k.nl):

As long as your app validates that csrfToken and it can only be used from a specific domain it should be good.
As such, unless the bot doesn’t send a valid csrfToken in it’s POST request, it won’t have any effect on mitigating spam.