Django Secured Fields
Django encrypted fields with search enabled.
Features
- Automatically encrypt/decrypt field value using cryptography's Fernet
- Built-in search lookup on the encrypted fields from hashlib's SHA-256 hash value.
in
and isnull
lookup also supported. - Supports most of available Django fields including
BinaryField
, JSONField
, and FileField
.
Installation
pip install django-secured-fields
Setup
-
Add secured_fields
into INSTALLED_APPS
INSTALLED_APPS = [
...
'secured_fields',
]
-
Generate a new key using for encryption
$ python manage.py generate_key
KEY: TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg=
HASH_SALT: 500d492e
-
Put generated key(s) and hash salt in settings
SECURED_FIELDS_KEY = 'TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg='
SECURED_FIELDS_KEY = [
'TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg=',
'...',
]
SECURED_FILDS_HASH_SALT = '500d492e'
Usage
Simple Usage
import secured_fields
phone_number = secured_fields.EncryptedCharField(max_length=10)
Enable Searching
import secured_fields
id_card_number = secured_fields.EncryptedCharField(max_length=18, searchable=True)
Supported Fields
EncryptedBinaryField
EncryptedBooleanField
EncryptedCharField
EncryptedDateField
EncryptedDateTimeField
EncryptedDecimalField
EncryptedFileField
EncryptedImageField
EncryptedIntegerField
EncryptedJSONField
EncryptedTextField
Settings
Key | Required | Default | Description |
---|
SECURED_FIELDS_KEY | Yes | | Key(s) for using in encryption/decryption with Fernet. Usually generated from python manage.py generate_key . For rotation keys, use a list of keys instead (see MultiFernet). |
SECURED_FIELDS_HASH_SALT | No | '' | Salt to append after the field value before hashing. Usually generated from python manage.py generate_key . |
SECURED_FIELDS_FILE_STORAGE | No | 'secured_fields.storage.EncryptedFileSystemStorage' | File storage class used for storing encrypted file/image fields. See EncryptedStorageMixin |
APIs
Field Arguments
Name | Type | Required | Default | Description |
---|
searchable | bool | No | False | Enable search function |
Encryption
> from secured_fields.fernet import get_fernet
> data = b'test'
> encrypted_data = get_fernet().encrypt(data)
> encrypted_data
b'gAAAAABh2_Ry_thxLTuFFXeMc9hNttah82979JPuMSjnssRB0DmbgwdtEU5dapBgISOST_a_egDc66EG_ZtVu_EqF_69djJwuA=='
> get_fernet().decrypt(encrypted_data)
b'test'
Rotate Keys
> from secured_fields.fernet import get_fernet
> encrypted_data = get_fernet().encrypt(b'test')
> encrypted_data
b'gAAAAABh2_Ry_thxLTuFFXeMc9hNttah82979JPuMSjnssRB0DmbgwdtEU5dapBgISOST_a_egDc66EG_ZtVu_EqF_69djJwuA=='
> rotated_encrypted_data = get_fernet().rotate(encrypted_data)
> get_fernet().decrypt(rotated_encrypted_data)
b'test'
See more details in MultiFernet.rotate.
EncryptedMixin
If you have a field which is not supported by the package, you can use EncryptedMixin
to enable encryption and search functionality for that custom field.
import secured_fields
from django.db import models
class EncryptedUUIDField(secured_fields.EncryptedMixin, models.UUIDField):
pass
task_id = EncryptedUUIDField(searchable=True)
EncryptedStorageMixin
If you use a custom file storage class (e.g. defined in settings.py
's DEFAULT_FILE_STORAGE
), you can enable file encryption using EncryptedStorageMixin
.
import secured_fields
from minio_storage.storage import MinioMediaStorage
class EncryptedMinioMediaStorage(
secured_fields.EncryptedStorageMixin,
MinioMediaStorage,
):
pass
Known Limitation
in
lookup on JSONField
is not available- Large files are not performance-friendly at the moment (see #2)
- Search on
BinaryField
does not supported at the moment (see #6) - Changing
searchable
value in a field with the records in the database is not supported (see #7)
Development
Requirements
- Docker
- Poetry
- MySQL Client
brew install mysql-client
echo 'export PATH="/usr/local/opt/mysql-client/bin:$PATH"' >> ~/.bash_profile
Running Project
-
Start backend databases
make up-db
-
Run tests (see: Testing)
Linting
make lint
Testing
make test-pg
Fix Formatting
make yapf