DEV Community

Cover image for Python Django: Create a more secure database by using a custom field
Dev Kadiem
Dev Kadiem

Posted on

Python Django: Create a more secure database by using a custom field

One way of enhancing the security of a database is by encrypting it. Luckily by utilizing Django, we can do this automatically. We only need the signing and models packages from the core Django packages.

Let's start by importing the required packages:

from django.core import signing
from django.db.models import TextField
Enter fullscreen mode Exit fullscreen mode

First, the signing is a cryptographic signing package; it allows encrypting and decrypting using the SECRET_KEY found in settings.py; more info can be found at the bottom, and we need the TextField because we will extend the default one with more functionality.


Now let's create and init the new field. I'll name it EncryptedTextField:

class EncryptedTextField(models.TextField):
    def __init__(self, *args, **kwargs):
        super(EncryptedTextField, self).__init__(*args, **kwargs)
Enter fullscreen mode Exit fullscreen mode

Now for the encrypting part:

    def get_db_prep_save(self, value, connection):
        value = super().get_db_prep_value(value, connection)
        if value is None:
            return value

        if len(value) == 0:
            return value

        return ((signing.dumps(str(value))).encode('utf-8')).decode('utf-8')
Enter fullscreen mode Exit fullscreen mode

The get_db_prep_save is a function that runs when we try to save data to the database; we are getting the raw data by get_db_prep_value and then return an encrypted version of it return ((signing.dumps(str(value))).encode('utf-8')).decode('utf-8'). More info can be found at the bottom.


Now for the decrypting part:

    def from_db_value(self, value, *args, **kwargs):
        if value is None:
            return value

        if len(value) == 0:
            return value

        return signing.loads(value)
Enter fullscreen mode Exit fullscreen mode

The def from_db_value is a function that runs when we try to get data from the database, value here represents the encrypted data, so we need to decrypt it, which is done here return signing.loads(value). More info can be found at the bottom.


Example of usage:

public_api = EncryptedTextField()
Enter fullscreen mode Exit fullscreen mode

Example of a full code:

from django.db.models import TextField
from django.core import signing

class EncryptedTextField(models.TextField):
    def __init__(self, *args, **kwargs):
        super(EncryptedTextField, self).__init__(*args, **kwargs)

    def get_db_prep_save(self, value, connection):
        value = super().get_db_prep_value(value, connection)
        if value is None:
            return value

        if len(value) == 0:
            return value

        return ((signing.dumps(str(value))).encode('utf-8')).decode('utf-8')

    def to_python(self, value):
        return value

    def from_db_value(self, value, *args, **kwargs):
        if value is None:
            return value

        if len(value) == 0:
            return value
        return signing.loads(value)
Enter fullscreen mode Exit fullscreen mode

Links to more info:

Top comments (0)