Django 개인정보 암호화 시스템 완벽 적용 가이드: Fernet + HMAC-SHA256 (2026 최신)
Django 개인정보 암호화가 왜 중요한가요? 사번, 이름 등과 같은 민감 개인정보를 DB에 저장할 때 반드시 암호화가 필수입니다. 이 포스트에서는 기존 프로젝트에서 실제 적용한 Django 개인정보 암호화 시스템을 상세히 공개합니다.
HMAC-SHA256 해시 + Fernet(AES-128) 대칭 암호화 + Custom EncryptedCharField를 조합한 실전 아키텍처를 코드와 함께 설명합니다. Django 개인정보 암호화를 처음 도입하는 중이시라면 이 가이드 하나로 끝낼 수 있습니다.
1. 프로젝트에서 Django 개인정보 암호화가 필요한 이유
일반적으로 기업에서 개발하는 대부분의 앱은 내부 직원(사번 기반) 인증 시스템입니다. 사번과 이름은 개인정보로 취급되며, DB 탈취 시 복호화가 불가능해야 개인정보보호법을 만족합니다.
Django 개인정보 암호화 전략 요약
- employee_no: HMAC-SHA256 해시 (복호화 불가, 인증·고유성 조회용)
- employee_no_plain: Fernet 암호화 (표시용, 복호화 가능)
- name: Fernet 암호화 (표시용)
- password: Django 기본 PBKDF2-SHA256 단방향 해시
이렇게 하면 DB가 유출되어도 키 없이는 어떤 정보도 복구할 수 없습니다.

2. Django 개인정보 암호화 핵심 전략 상세 비교
| Fields | 저장 방식 | 용도 | 복호화 가능? |
|---|---|---|---|
| employee_no | HMAC-SHA256 해시 | 로그인·조회 | 불가 |
| employee_no_plain | Fernet 암호문 | 관리자 화면 표시 | Yes |
| name | Fernet 암호문 | 표시·검색 | Yes |
| password | PBKDF2-SHA256 | 로그인 인증 | 불가 |
Django 개인정보 암호화의 핵심은 “조회용은 해시, 표시용은 대칭 암호화”를 분리하는 것입니다.
3. HMAC-SHA256 구현 (employee_no 보호)
# apps/accounts/encryption.py
# HMAC-SHA256을 이용한 employee_no 해시 생성 함수
# 목적: 사번을 평문으로 DB에 저장하지 않고 단방향 해시로 저장
# → DB가 유출되어도 원본 사번을 복구할 수 없도록 보안 강화
import hashlib
import hmac as _hmac
from django.conf import settings
def hmac_of(value: str) -> str:
"""
입력된 평문 사번을 HMAC-SHA256 해시로 변환하여 반환합니다.
- KEY: settings.FIELD_HMAC_KEY (환경변수로 관리, Git에 절대 커밋 금지)
- 복호화가 불가능한 단방향 해시 → 로그인 시 조회용으로만 사용
- 동일한 사번은 항상 동일한 해시값이 생성되어 중복 가입 방지
"""
# 설정에서 HMAC 키를 가져옴 (str 또는 bytes 모두 지원)
key = settings.FIELD_HMAC_KEY
return _hmac.new(
key.encode() if isinstance(key, str) else key, # 키를 bytes로 변환
value.encode(), # 입력 사번을 bytes로 변환
hashlib.sha256 # SHA256 알고리즘 사용
).hexdigest() # 64자리 hex 문자열로 반환회원가입 시 employee_no = hmac_of(plain_no)로 저장해 복호화 불가능하게 만듭니다.
4. Fernet 암호화 + Custom EncryptedCharField (가장 강력한 Django 개인정보 암호화 기법)
# apps/accounts/fields.py
# Fernet 암호화를 Django 모델 필드에서 투명하게 사용할 수 있게 해주는 커스텀 필드
# 특징: 모델 코드에서는 평문처럼 사용해도 DB에는 자동으로 암호문이 저장됨
from django.db import models
from .encryption import encrypt_value, decrypt_value
class EncryptedCharField(models.TextField):
"""
Django에서 개인정보(이름, 사번 평문 등)를 Fernet으로 암호화해서 저장하는 커스텀 필드
- DB에는 암호문(ciphertext)만 저장
- Python 코드에서는 평문(plaintext)으로 자동 변환되어 사용 가능
- NSCG 준수에 필수적인 투명 암호화(Transparent Encryption) 구현
"""
def from_db_value(self, value, expression, connection):
"""
DB에서 데이터를 읽어올 때 자동으로 복호화하는 메서드
- value: DB에 저장된 암호문
- decrypt_value() 호출 → 평문 반환
"""
return decrypt_value(value) if value is not None else value
def get_prep_value(self, value):
"""
DB에 저장하기 직전에 자동으로 암호화하는 메서드
- value: 모델에서 입력된 평문
- encrypt_value() 호출 → 암호문으로 변환 후 DB에 저장
"""
if value is None or value == '':
return value
return encrypt_value(value)Django 개인정보 암호화의 핵심 Custom Field입니다. 모델에서 평문처럼 사용해도 DB에는 자동 암호문이 저장됩니다.

5. encryption.py 전체 유틸리티 (실전 코드)
# apps/accounts/encryption.py
# Fernet (AES-128 기반) 대칭 암호화 관련 핵심 유틸리티 모음
# 모든 개인정보 암호화·복호화 작업은 이 파일을 통해 중앙 집중 관리
from cryptography.fernet import Fernet, InvalidToken
from django.conf import settings
def _fernet() -> Fernet:
"""
Fernet 인스턴스를 생성하는 내부 헬퍼 함수
- settings.FIELD_ENCRYPTION_KEY를 사용해 Fernet 객체 생성
- 매번 새로 생성하지 않고 필요할 때마다 호출 (성능과 보안 균형)
"""
key = settings.FIELD_ENCRYPTION_KEY
# 키가 str이면 bytes로 변환 (Fernet은 bytes 키만 허용)
return Fernet(key.encode() if isinstance(key, str) else key)
def encrypt_value(plain: str) -> str:
"""
평문 데이터를 Fernet으로 암호화하여 반환
- 빈 문자열이나 None은 그대로 반환 (오류 방지)
- 실제 DB에 저장될 암호문 생성
"""
if not plain:
return plain
return _fernet().encrypt(plain.encode()).decode() # bytes → str 변환
def decrypt_value(cipher: str) -> str:
"""
Fernet 암호문을 복호화하여 평문으로 반환
- InvalidToken 예외 발생 시 원본 암호문을 그대로 반환
→ 마이그레이션 전 기존 평문 데이터와의 호환성을 위해 필수
"""
if not cipher:
return cipher
try:
return _fernet().decrypt(cipher.encode()).decode()
except (InvalidToken, Exception):
# 복호화 실패 시 (키 변경, 마이그레이션 전 데이터 등) 원본 반환
return cipher6. .env + settings.py 설정 (키 관리 필수)
FIELD_ENCRYPTION_KEY=your_44char_fernet_key_here==
FIELD_HMAC_KEY=your_64char_hex_hmac_key_hereDjango 개인정보 암호화에서 가장 중요한 것은 키를 절대 Git에 커밋하지 말고 환경변수 또는 secrets manager에 보관하는 것입니다.

7. DB 정기 백업도 Fernet으로 암호화 (완전 보안)
python manage.py backup_db 커맨드로 MySQL/SQLite를 Fernet 암호화된 .enc 파일로 백업합니다.
cPanel Cron으로 매일 새벽 자동 실행 → DB 백업 파일도 안전in the file.

8. CustomUser 모델과 Admin 검색/승인 기능
CustomUser 모델에서 EncryptedCharField를 사용하고, Admin에서 get_search_results 오버라이드하여 평문 검색이 가능하도록 구현했습니다.

결론: Django 개인정보 암호화로 개인정보보호법 완벽 준수
Django 개인정보 암호화 시스템을 프로젝트에 적용하면 DB 유출 사고에도 개인정보가 안전하게 보호됩니다. HMAC + Fernet + Custom Field + 암호화 백업 조합은 현재 Django에서 가장 실전적이고 강력한 방법입니다.
오늘 바로 Django 개인정보 암호화를 여러분 프로젝트에 도입해 보세요. 개인정보보호법, GDPR 준수까지 한 번에 해결할 수 있습니다!
출처 리스트
- Django Official Documentation: Password management and hashing (PBKDF2-SHA256)
- Medium: “How to Encrypt Sensitive Data with Python/Django” (Anil Kumar Valluru)
- Django Forum: Encryption techniques in database using Fernet (2025)
- GitHub: jazzband/django-fernet-encrypted-fields 공식 저장소 및 문서
- Stack Overflow: Creating custom Django encrypted field with Fernet
- Medium: “Encrypt Sensitive Data in Django REST APIs” (Fahim Ad)
- Reintech: Working with File Encryption in Django
- Django-fernet-fields Official Docs: Field-level encryption best practices






