georgemarshall / django-cryptography

Easily encrypt data in Django
https://django-cryptography.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
371 stars 70 forks source link

Encrypting ForeignKeys #46

Open desertSniper87 opened 4 years ago

desertSniper87 commented 4 years ago

How do I encrypt ForeignKey fields? I have tried something like this:

medicine = encrypt(models.ForeignKey(to='assessment.Medication', on_delete=models.CASCADE))

But I am getting errors which is encountered during circular import.

django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.

Full error:

Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/utils/autoreload.py", line 54, in wrapper
    fn(*args, **kwargs)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/core/management/commands/runserver.py", line 109, in inner_run
    autoreload.raise_last_exception()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/utils/autoreload.py", line 77, in raise_last_exception
    raise _exception[1]
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/core/management/__init__.py", line 337, in execute
    autoreload.check_errors(django.setup)()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/utils/autoreload.py", line 54, in wrapper
    fn(*args, **kwargs)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/registry.py", line 114, in populate
    app_config.import_models()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/config.py", line 211, in import_models
    self.models_module = import_module(models_module_name)
  File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/torsho/employeeHealthAssessmentApp/assessment/models.py", line 199, in <module>
    class Prescription(models.Model):
  File "/home/torsho/employeeHealthAssessmentApp/assessment/models.py", line 209, in Prescription
    medicine = encrypt(models.ForeignKey(to='assessment.models.Medication', on_delete=models.CASCADE))
  File "/home/torsho/employeeHealthAssessmentApp/django_cryptography/fields.py", line 216, in encrypt
    name, path, args, kwargs = base_field.deconstruct()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/db/models/fields/related.py", line 856, in deconstruct
    name, path, args, kwargs = super().deconstruct()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/db/models/fields/related.py", line 583, in deconstruct
    swappable_setting = self.swappable_setting
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/db/models/fields/related.py", line 374, in swappable_setting
    return apps.get_swappable_settings_name(to_string)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/registry.py", line 288, in get_swappable_settings_name
    for model in self.get_models(include_swapped=True):
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/registry.py", line 178, in get_models
    self.check_models_ready()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/registry.py", line 140, in check_models_ready
    raise AppRegistryNotReady("Models aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
Exception in thread django-main-thread:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/utils/autoreload.py", line 54, in wrapper
    fn(*args, **kwargs)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/core/management/commands/runserver.py", line 109, in inner_run
    autoreload.raise_last_exception()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/utils/autoreload.py", line 77, in raise_last_exception
    raise _exception[1]
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/core/management/__init__.py", line 337, in execute
    autoreload.check_errors(django.setup)()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/utils/autoreload.py", line 54, in wrapper
    fn(*args, **kwargs)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/__init__.py", line 24, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/registry.py", line 114, in populate
    app_config.import_models()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/config.py", line 211, in import_models
    self.models_module = import_module(models_module_name)
  File "/usr/lib/python3.8/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1014, in _gcd_import
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 783, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/home/torsho/employeeHealthAssessmentApp/assessment/models.py", line 199, in <module>
    class Prescription(models.Model):
  File "/home/torsho/employeeHealthAssessmentApp/assessment/models.py", line 209, in Prescription
    medicine = encrypt(models.ForeignKey(to='assessment.models.Medication', on_delete=models.CASCADE))
  File "/home/torsho/employeeHealthAssessmentApp/django_cryptography/fields.py", line 216, in encrypt
    name, path, args, kwargs = base_field.deconstruct()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/db/models/fields/related.py", line 856, in deconstruct
    name, path, args, kwargs = super().deconstruct()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/db/models/fields/related.py", line 583, in deconstruct
    swappable_setting = self.swappable_setting
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/db/models/fields/related.py", line 374, in swappable_setting
    return apps.get_swappable_settings_name(to_string)
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/registry.py", line 288, in get_swappable_settings_name
    for model in self.get_models(include_swapped=True):
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/registry.py", line 178, in get_models
    self.check_models_ready()
  File "/home/torsho/employeeHealthAssessmentApp/env/lib/python3.8/site-packages/django/apps/registry.py", line 140, in check_models_ready
    raise AppRegistryNotReady("Models aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
frost-nzcr4 commented 3 years ago

Try to use laziness from django.utils.functional import lazy; medicine = lazy(encrypt(models.ForeignKey(to='assessment.Medication', on_delete=models.CASCADE)))

thismatters commented 3 years ago

I don't think it will work to encrypt foreignkeys; django relies on them for all kinds of database optimizations. General advice is to encrypt all the PII that might make knowledge of the foreignkey'd ID personally identifiable. Encrypting the sensitive data means that you shouldn't have to encrypt metadata.