Lately I’ve been learning web development with Django. I have a few projects I’ve been working on and have learned a ton. Something I came across in one of my projects was the need to encrypt fields in the database. Being a DevOps/Security guy I know the whole arguments against and for using encryption on specific database fields. In this case I am storing some usernames and passwords for a site I am scraping, and felt that encryption was better than nothing. I found an article but didn’t like the exact way they were implementing the encryption so I changed it. Below is that implementation:
class EncryptedText(models.TextField):
description = "An encrypted text field for storing sensitive information"
def __init__(self, *args, **kwargs):
self.__key = os.environ.get('FERNET_KEY', None)
if self.__key is None:
raise ValueError('No FERNET_KEY environment variable found!')
super().__init__(*args, **kwargs)
def deconstruct(self):
name, key, args, kwargs = super().deconstruct()
return name, key, args, kwargs
def from_db_value(self, value, expression, connection):
if self.__key and value:
value = base64.b64decode(value)
f = Fernet(self.__key)
value = f.decrypt(value)
return value
def to_python(self, value):
return value
def get_db_prep_value(self, value, connection, prepared=False):
if value:
if self.__key:
f = Fernet(self.__key)
value = f.encrypt(value.encode())
value = base64.b64encode(value).decode('utf-8')
return value
The biggest modification I made was changing the way the key was stored. In the article I found they used a file on the filesystem to store the key. Being that I would likely deploy this to some containerization service (Kubernetes, Heroku, etc.) filesystem storage is a no-no as any app rebuild would destroy the filesystem and render my data unreadable. This change instead uses the environment variable FERNET_KEY
.
If you want to look at the original article you can here: https://dadruid5.com/2018/08/28/encrypting-data-in-django-with-the-fernet-algorithm/