Django Simple Captcha Example: Protecting Your Login Forms

django simple captcha

Introdcution

When it comes to security features on the login pages, it is common to remind about password creation policies and two-factor or multi-factor authentication controls as well as data encryption.

However, there is another aspect of security that we overlook most of the time which could change the game-Captcha. This is one of the things that you have seen a thousand times but what is the point and why do you have to use it on the login page? Let us find out.

django simple captcha example
Captcha

A Brief Explanation Why Users Should Care About Captcha Also, the things, as in, the attacks are only getting more and more complex as with every passing day. Brute force is among the very many strategies employed by a hacker with the help of a bot.

This technique involves guessing the password by trial and error by trying all possible combinations until hitting it right. A properly deployed CAPTCHA prevents such bots from succeeding since it works more towards separating the human users from the machine users.

Strike out CAPTCHA in your mind as an aggressive gatekeeper. Rather, it is a polite security moderator who intervenes when it’s proper while quantifying it using the simple inquiry “Are you a human?“.

Setting Up Django for CAPTCHA

However first as always, let us do some housekeeping on our Django project before we add CAPTCHA. First off let’s create a virtual environment where we will keep your dependencies in check. You can do that with .

Bash
$ python -m venv myenv
$ source myenv/bin/activate  # On Windows: myenv\Scripts\activate

Now let’s install Django using pip.

Bash
$ pip install django

After this, we will need to install django-simple-captcha since this is the library that is going to provide the CAPTCHAS features.

Bash
$ pip install django-simple-captcha

With the libraries installed, let’s structure our project. If you haven’t already, create a new Django project.

Bash
$ django-admin startproject myproject

In this project let’s create an app named accounts which will be used for login and management of CAPTCHA.

Bash
$ python manage.py startapp accounts

Now go to the INSTALLED_APPS section in settings.py file of your project and include both accounts and captcha that were created.

INSTALLED_APPS = [
    ...
    'accounts',
    'captcha',
]

After that, to create the necessary tables for CaptchaStore, we need to run the following commands in your terminal.

Bash
$ python manage.py migrate

The structure of the app accounts would have now been created in our project directory which is meant to incorporate CAPTCHA to login pages.

Writing the Code

In this section, we’ll walk through the code needed to implement a CAPTCHA-protected login form in Django. By the end of this, we’ll have a secure login page that includes a CAPTCHA challenge to prevent bots from accessing our system.

The View

Let’s start by creating the view that handles the login process. Here’s the code.

from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib import messages
from captcha.helpers import captcha_image_url
from captcha.models import CaptchaStore

def UserLogin(request):
    if request.method == "POST":
        username = request.POST.get("username")
        password = request.POST.get("password")
        captcha_key = request.POST.get("captcha_0")  # Captcha key
        captcha_value = request.POST.get("captcha_1")  # User-entered captcha text

        # Validate CAPTCHA
        try:
            captcha_obj = CaptchaStore.objects.get(hashkey=captcha_key)
            if captcha_obj.response.lower() != captcha_value.lower():
                messages.error(request, "Invalid CAPTCHA.")
                return redirect("captcha-login")
        except CaptchaStore.DoesNotExist:
            messages.error(request, "Invalid CAPTCHA.")
            return redirect("captcha-login")

        # Authenticate user
        user_auth = authenticate(request, username=username, password=password)
        if user_auth is not None:
            login(request, user_auth)
            return redirect("dashboard")
        else:
            messages.error(request, "Invalid username or password.")
            return redirect("captcha-login")

    # Generate CAPTCHA for GET requests
    captcha_key = CaptchaStore.generate_key()
    captcha_image = captcha_image_url(captcha_key)

    context = {"captcha_image": captcha_image, "captcha_key": captcha_key}
    return render(request, "login.html", context)

In this view, we are handling both the CAPTCHA generation and the login process. When a user submits their credentials, we retrieve the entered username and password, as well as the CAPTCHA values. The CAPTCHA is validated using Django’s CaptchaStore, and if it’s incorrect, an error message is displayed. If the CAPTCHA and credentials are correct, we log the user in.

NB: For the redirect("dashboard") part in the view, make sure to create your own dashboard view and template, as it is not defined in this article.

The URL Configuration

Next, we need to map the view to a URL. Here’s how we can add this in our urls.py.

from django.contrib import admin
from django.urls import path, include
from accounts.views import UserLogin

urlpatterns = [
    path('admin/', admin.site.urls),
    path('captcha/', include('captcha.urls')),
    path('', UserLogin, name='captcha-login')
]

We include the necessary CAPTCHA URLs and connect our login view to the root path (”). This way, when users visit the login page, they’ll be presented with the CAPTCHA form.

The URL Configuration

Finally, let’s set up the HTML template that renders the form. This will include the fields for the username, password, and CAPTCHA.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login Page</title>
    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<div class="container">
    <div class="row justify-content-center">

        {% if messages %}
            {% for message in messages %}
                <div class="alert alert-danger alert-dismissible">
                    <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
                    {{ message }}
                </div>
            {% endfor %}
        {% endif %}

        <div class="col-md-4">
            <h3 class="text-center mt-5">Django Captcha</h3>
            <hr>
            <form method="POST">
                {% csrf_token %}
                
                <!-- Email Input -->
                <div class="mb-3">
                    <label for="username" class="form-label">Email address</label>
                    <input type="text" class="form-control" id="username" name="username" required>
                </div>

                <!-- Password Input -->
                <div class="mb-3">
                    <label for="password" class="form-label">Password</label>
                    <input type="password" class="form-control" id="password" name="password" required>
                </div>

                <!-- CAPTCHA Field -->
                <div class="mb-3">
                    <img src="{{ captcha_image }}" class="mb-2" alt="CAPTCHA Image" id="captcha-image">
                    <input type="text" name="captcha_1" id="captcha" class="form-control mt-2" placeholder="Enter CAPTCHA">
                    <input type="hidden" name="captcha_0" value="{{ captcha_key }}">
                </div>

                <!-- Submit Button -->
                <div class="d-grid">
                    <button type="submit" class="btn btn-primary">Login</button>
                </div>
            </form>
        </div>
    </div>
</div>

<!-- Bootstrap JS and dependencies -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

This template integrates Bootstrap for styling and includes a form with fields for the username, password, and CAPTCHA. When users submit the form, it sends a POST request back to the UserLogin view to handle validation and authentication.

By following these steps, we’ve successfully built a CAPTCHA-protected login page in Django. This will help us prevent automated bots from attempting unauthorized logins and keep our system secure.

django simple captcha example
http://127.0.0.1:8000/

Customizing the CAPTCHA

Now that we have added the simple CAPTCHA to our login system we can change how it looks or works to fit our design or needs better. Here is how we can adjust different parts of the CAPTCHA.

Changing CAPTCHA Settings

With Django’s django-simple-captcha package we can change different settings in the settings.py file. By adjusting these settings we can decide how the CAPTCHA appears how hard the challenge is and how long it stays active.

Here are some settings that are often changed.

CAPTCHA_FONT_SIZE = 30  # Change the font size of the CAPTCHA text
CAPTCHA_LENGTH = 8  # Increase or decrease the number of characters in the CAPTCHA
CAPTCHA_TIMEOUT = 5  # The CAPTCHA expiration time in minutes
CAPTCHA_IMAGE_SIZE = (350, 80)  # Change the size of the CAPTCHA image
CAPTCHA_BACKGROUND_COLOR = 'blue'  # Set the background color
CAPTCHA_FOREGROUND_COLOR = 'yellow'  # Set the text color

These options help us change how the CAPTCHA looks and how hard it is for bots to solve. By making the CAPTCHA longer it becomes more challenging for bots. We can also adjust the font size and image size to make sure the CAPTCHA fits our design.

Adding Custom CAPTCHA Styles

To make the CAPTCHA image look even more unique we can create custom styles using CSS in our template. For example we can change the colors or borders of the CAPTCHA.

<style>
    #captcha-image {
        border: 2px solid #007bff;  /* Adding a border around the CAPTCHA */
        border-radius: 5px;
        padding: 5px;
        background-color: #f8f9fa;  /* Light background behind the image */
    }
</style>

This special CSS code will help us blend the CAPTCHA more smoothly into the login page’s design.

Adding Custom CAPTCHA Styles

Another helpful feature we can include is refreshing the CAPTCHA image without having to reload the whole page. This can make it easier for users to read the CAPTCHA if it’s hard to see.

We can put a “Refresh” link next to the CAPTCHA image to do this.

<a href="#" onclick="document.getElementById('captcha-image').src = '{{ captcha_image }}' + '?' + Math.random(); return false;">Refresh CAPTCHA</a>

This JavaScript code forces the browser to reload the CAPTCHA image when the user clicks the link.

django simple captcha example
http://127.0.0.1:8000/

Conclusion

Adding CAPTCHA to a Django app stops robots from getting into user accounts or sending spam. Developers can quickly put this security feature on their website forms with tools like django-simple-captcha.

This makes sure that only real people can get to important parts of the site keeping user information safe and making the app more dependable. It’s really important for developers to use CAPTCHA to keep their web apps safe and reliable especially with online security risks always changing.

🧷Explore the complete source code on GitHub.


Light
×