Laravel 11 - Honeypot

Touseef Afridi
16 Sep 24

Laravel 11 - Honeypot

In this tutorial, we'll explore how to integrate the Honeypot package in Laravel 11, providing an effective way to prevent bots from submitting forms.


If you're a video person, feel free to skip the post and check out the video instead!


Quick Overview

This guide walks you through setting up honeypot protection in a Laravel application. We start by creating a new Laravel project and installing the Spatie Honeypot package to prevent form spam. After configuring the honeypot package and setting up the honeypot field in the configuration file, we create a simple contact form and apply the honeypot protection using the Blade directive. We then define routes for displaying the form and handling submissions, applying the honeypot middleware to block bots. Finally, we test the honeypot functionality by submitting the form and simulating a bot attack, with custom responses to detect and handle bot submissions. This tutorial provides a straightforward way to integrate spam protection into your Laravel forms.

Step # 1 : Set Up the Laravel Project.

Start by creating a new Laravel app or using an existing one. To create a new project, run.
laravel new honeypot
Alternatively, you can use Composer by running the command.
composer create-project laravel/laravel --prefer-dist honeypot
During setup, follow these options to match our stack.
  • Choose None when asked for a Starter Kit.
  • Select Pest as the testing framework.
  • Use MySQL for the database.
  • Type yes when prompted to run default migrations.

This will initialize a fresh Laravel project named honeypot, configured specifically for our needs. With Pest set up for testing and MySQL connected as the database, we now have a solid foundation to start implementing and testing the honeypot protection for our forms, ensuring spam submissions are effectively blocked.

Step # 2 : Access the project.

Open a terminal (e.g., Git Bash) and navigate to your Laravel project's root folder.
cd c:xampp/htdocs/honeypot
Once you're in the project folder, you're ready to start running commands and setting up your application.

Step # 3 : Install the Honeypot Package.

To add spam protection to your forms, install the Honeypot package by Spatie. This package helps prevent bots from submitting forms by using invisible fields and time-based validation. Run the following command in your project root.
composer require spatie/laravel-honeypot
Once installed, you’ll be able to integrate honeypot protection into your forms with minimal effort.

Step # 4 : Publish the Honeypot Configuration.

After installing the package, publish its configuration file to customize its behavior based on your application’s needs. This step makes the default settings available in your project so you can tweak things like field names and response time thresholds. Run the following command.
php artisan vendor:publish --provider="Spatie\Honeypot\HoneypotServiceProvider" --tag=honeypot-config
This will create a honeypot.php file in the config directory, allowing you to adjust the settings as needed.

Step # 5 : Configure the Honeypot Field Name.

To customize how the honeypot behaves, open the configuration file located at: config/honeypot.php. Look for the name_field_name setting. This defines the name of the invisible honeypot input field that bots shouldn’t fill. If a bot submits this field with a value, the request will be rejected. You can update it as needed. For example, change.
'name_field_name' => env('HONEYPOT_NAME', 'my_name')
To:
'name_field_name' => env('HONEYPOT_NAME', 'complete_name'),
Here you can specify name of the honeypot field. Make sure the honeypot field name doesn’t match any actual input field used in your form to avoid conflicts.

Step # 6 : Create a View.

To test the honeypot protection, create a simple contact form view. This form will allow users to submit their name and message, and later we’ll apply honeypot validation to prevent spam submissions. Create a new Blade file at: resources/views/contact.blade.php and add the following code.
<!DOCTYPE html>
<html>
<head>
    <title>Laravel - Honeypot - Code Shotcut</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</head>
<body class="bg-white">
    <div class="container mt-5">
        <div class="row">
            <div class="col-12 mt-5">
                <h3 class="mt-5 mb-5">Contact Us</h3>
                @if(session()->has('success'))
                <div class="alert alert-success">
                    {{ session('success') }}
                </div>
                @endif
                @if(session()->has('error'))
                <div class="alert alert-danger">
                    {{ session('error') }}
                </div>
                @endif
                <form method="post" action="{{ url('/message') }}">
                    @csrf
                    <div class="form-group">
                        <label for="name">Name</label>
                        <input type="text" class="form-control" name="name" id="name" placeholder="Enter Name">
                        <small id="name_help" class="form-text text-muted"></small>
                    </div>
                    <div class="form-group">
                        <label for="message">Message</label>
                        <textarea class="form-control" name="message" id="message" placeholder="Your Message."></textarea>
                        <small id="name_help" class="form-text text-muted"></small>
                    </div>
                    <button type="submit" class="btn btn-primary">Submit</button>
                </form>
            </div>
        </div>
    </div>
</body>
</html>
This contact form sets the stage for implementing honeypot protection, it’s where we’ll catch and block bots before they ever hit our backend.

Step # 7 : Set Up Routes and Apply Honeypot Middleware.

We’ll define two routes. One to display the contact form and another to handle form submissions with honeypot spam protection applied. First, import the required classes at the top of your web.php file.
use Illuminate\Http\Request;
use Spatie\Honeypot\ProtectAgainstSpam;
Then, define the routes.
// Display the contact form
Route::get('/', function () {
    return view('contact');
});
// Handle the form submission with validation and honeypot protection
Route::post('/message', function (Request $request) {
    $request->validate([
        'name' => 'required|string|max:100',
        'message' => 'required|string|max:500',
    ]);
    return redirect()->back()->with('success', 'Request validated successfully');
})->middleware(ProtectAgainstSpam::class);
The GET route is responsible for rendering the contact form view, allowing users to access and fill out the form. The POST route handles form submissions by validating the incoming data and applying the ProtectAgainstSpam middleware. This middleware automatically detects and blocks spammy bot requests based on hidden honeypot fields, preventing them from reaching your application logic.

Step # 8 : Apply Honeypot Protection in the Form.

You can use the @honeypot Blade directive to protect the form.
<form method="POST" action="{{ route('contactForm.submit') }}">
    @honeypot
    <input name="myField" type="text">
</form>
Or, you can add the <x-honeypot /> Blade component to any form you wish to protect.
<form method="POST" action="{{ route('contactForm.submit') }}">
    <x-honeypot />
    <input name="myField" type="text">
</form>
This will add a hidden input field with the name defined in the config file. By default, it will use my_name and timestamp. Let's update our contact form in contact.blade.php to use honeypot.
<form method="post" action="{{ url('/message') }}">
    @csrf
    <!-- Add Honeypot blade directive -->
    @honeypot
    <div class="form-group">
        <label for="name">Name</label>
        <input type="text" class="form-control" name="name" id="name" placeholder="Enter Name">
    </div>
    <div class="form-group">
        <label for="message">Message</label>
        <textarea class="form-control" name="message" id="message" placeholder="Your Message."></textarea>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
</form>
Honeypot protection is applied to the form using either the @honeypot Blade directive or the <x-honeypot /> component. Both methods automatically insert a hidden input field, configured in the honeypot.php file, which helps identify and block spam submissions. This ensures that any automated bots trying to fill in the hidden field will be caught and prevented from submitting the form.

Step # 9 : It's time to test.

Start the Laravel development server using the command.
php artisan serve
Access the URL: 127.0.0.1:8000. Inspect the form, and you should see a hidden field named complete_name_hash.

Now, test the basic form submission.

Spam bots will also fill in hidden fields. To simulate this, let’s fill the hidden field and trigger an error using the BlankPageResponder class. Search for the file BlankPageResponder.php and update it as follows.
<?php
namespace Spatie\Honeypot\SpamResponder;
use Closure;
use Illuminate\Http\Request;
class BlankPageResponder implements SpamResponder
{
    public function respond(Request $request, Closure $next)
    {
        return redirect()->back()->with('error', 'Bot detected');
    }
}



If you want to integrate the Spatie\Honeypot\ProtectAgainstSpam middleware with Laravel’s built-in authentication routes, wrap the Auth::routes(); declaration with the appropriate middleware group (make sure to add the @honeypot directive to the authentication forms)
use Spatie\Honeypot\ProtectAgainstSpam;
Route::middleware(ProtectAgainstSpam::class)->group(function() {
    Auth::routes();
});

Conclusion

By following this guide, you've successfully integrated honeypot protection into your Laravel application to prevent spam submissions. You set up a fresh Laravel project, installed the Spatie Honeypot package, and configured it to work seamlessly with your contact form. You've also applied the honeypot protection using the Blade directive and ensured that bot submissions are blocked with custom error responses. This simple yet effective approach to spam prevention can be extended to other forms in your application. Moving forward, you can explore adding more advanced validation or other anti-spam measures to further secure your app.
For more details, please refer to the Spatie Honeypot package documentation.
Share this with friends!


"Give this post some love and slap that 💖 button as if it owes you money! 💸😄"
0

0 Comments

To engage in commentary, kindly proceed by logging in or registering