Django encrypted fields with search enabled.
- 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
andisnull
lookup also supported. - Supports most of available Django fields including
BinaryField
,JSONField
, andFileField
.
pip install django-secured-fields
-
Add
secured_fields
intoINSTALLED_APPS
# settings.py 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
# settings.py SECURED_FIELDS_KEY = 'TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg=' # or multiple keys for rotation SECURED_FIELDS_KEY = [ 'TtY8MAeXuhdKDd1HfGUwim-vQ8H7fXyRQ9J8pTi_-lg=', '...', ] # optional SECURED_FILDS_HASH_SALT = '500d492e'
# models.py
import secured_fields
phone_number = secured_fields.EncryptedCharField(max_length=10)
# models.py
import secured_fields
id_card_number = secured_fields.EncryptedCharField(max_length=18, searchable=True)
EncryptedBinaryField
EncryptedBooleanField
EncryptedCharField
EncryptedDateField
EncryptedDateTimeField
EncryptedDecimalField
EncryptedFileField
EncryptedImageField
EncryptedIntegerField
EncryptedJSONField
EncryptedTextField
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 |
Name | Type | Required | Default | Description |
---|---|---|---|---|
searchable |
bool |
No | False |
Enable search function |
> 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'
> 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.
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)
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
in
lookup onJSONField
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)
- Docker
- Poetry
- MySQL Client
brew install mysql-client
echo 'export PATH="/usr/local/opt/mysql-client/bin:$PATH"' >> ~/.bash_profile
-
Start backend databases
make up-db
-
Run tests (see: Testing)
make lint
make test-pg # or make test-mysql, make test-sqlite
make yapf