{"id":6436,"date":"2026-06-01T22:25:49","date_gmt":"2026-06-01T13:25:49","guid":{"rendered":"https:\/\/secondlife.lol\/?p=6436"},"modified":"2026-06-01T22:25:52","modified_gmt":"2026-06-01T13:25:52","slug":"django-personal-data-encryption-fernet-hmac-2026","status":"publish","type":"post","link":"https:\/\/secondlife.lol\/ja\/django-personal-data-encryption-fernet-hmac-2026\/","title":{"rendered":"Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654 \uc2dc\uc2a4\ud15c \uc644\ubcbd \uc801\uc6a9 \uac00\uc774\ub4dc: Fernet + HMAC-SHA256 (2026 \ucd5c\uc2e0)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong><a href=\"https:\/\/www.djangoproject.com\/\" target=\"_blank\" rel=\"noopener\">Django<\/a> \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654<\/strong>\uac00 \uc65c \uc911\uc694\ud55c\uac00\uc694? <strong>\uc0ac\ubc88, \uc774\ub984<\/strong> \ub4f1\uacfc \uac19\uc740 \ubbfc\uac10 \uac1c\uc778\uc815\ubcf4\ub97c DB\uc5d0 \uc800\uc7a5\ud560 \ub54c <strong>\ubc18\ub4dc\uc2dc \uc554\ud638\ud654<\/strong>\uac00 \ud544\uc218\uc785\ub2c8\ub2e4. \uc774 \ud3ec\uc2a4\ud2b8\uc5d0\uc11c\ub294 <strong>\uae30\uc874 \ud504\ub85c\uc81d\ud2b8<\/strong>\uc5d0\uc11c \uc2e4\uc81c \uc801\uc6a9\ud55c <strong>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654 \uc2dc\uc2a4\ud15c<\/strong>\uc744 \uc0c1\uc138\ud788 \uacf5\uac1c\ud569\ub2c8\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">HMAC-SHA256 \ud574\uc2dc + Fernet(AES-128) \ub300\uce6d \uc554\ud638\ud654 + Custom EncryptedCharField\ub97c \uc870\ud569\ud55c <strong>\uc2e4\uc804 \uc544\ud0a4\ud14d\ucc98<\/strong>\ub97c \ucf54\ub4dc\uc640 \ud568\uaed8 \uc124\uba85\ud569\ub2c8\ub2e4. <strong>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654<\/strong>\ub97c \ucc98\uc74c \ub3c4\uc785\ud558\ub294 \uc911\uc774\uc2dc\ub77c\uba74 \uc774 \uac00\uc774\ub4dc \ud558\ub098\ub85c \ub05d\ub0bc \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. \ud504\ub85c\uc81d\ud2b8\uc5d0\uc11c Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654\uac00 \ud544\uc694\ud55c \uc774\uc720<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\uc77c\ubc18\uc801\uc73c\ub85c \uae30\uc5c5\uc5d0\uc11c \uac1c\ubc1c\ud558\ub294 \ub300\ubd80\ubd84\uc758 \uc571\uc740 \ub0b4\ubd80 \uc9c1\uc6d0(\uc0ac\ubc88 \uae30\ubc18) \uc778\uc99d \uc2dc\uc2a4\ud15c\uc785\ub2c8\ub2e4. \uc0ac\ubc88\uacfc \uc774\ub984\uc740 <strong>\uac1c\uc778\uc815\ubcf4<\/strong>\ub85c \ucde8\uae09\ub418\uba70, DB \ud0c8\ucde8 \uc2dc \ubcf5\ud638\ud654\uac00 \ubd88\uac00\ub2a5\ud574\uc57c \uac1c\uc778\uc815\ubcf4\ubcf4\ud638\ubc95\uc744 \ub9cc\uc871\ud569\ub2c8\ub2e4.<\/p>\n\n\n<style>.wp-block-kadence-advancedheading.kt-adv-heading6436_2df471-a5, .wp-block-kadence-advancedheading.kt-adv-heading6436_2df471-a5[data-kb-block=\"kb-adv-heading6436_2df471-a5\"]{font-style:normal;}.wp-block-kadence-advancedheading.kt-adv-heading6436_2df471-a5 mark.kt-highlight, .wp-block-kadence-advancedheading.kt-adv-heading6436_2df471-a5[data-kb-block=\"kb-adv-heading6436_2df471-a5\"] mark.kt-highlight{font-style:normal;color:#f76a0c;-webkit-box-decoration-break:clone;box-decoration-break:clone;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.wp-block-kadence-advancedheading.kt-adv-heading6436_2df471-a5 img.kb-inline-image, .wp-block-kadence-advancedheading.kt-adv-heading6436_2df471-a5[data-kb-block=\"kb-adv-heading6436_2df471-a5\"] img.kb-inline-image{width:150px;vertical-align:baseline;}<\/style>\n<h3 class=\"kt-adv-heading6436_2df471-a5 wp-block-kadence-advancedheading\" data-kb-block=\"kb-adv-heading6436_2df471-a5\"><strong>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654<\/strong> \uc804\ub7b5 \uc694\uc57d<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>employee_no<\/strong>: HMAC-SHA256 \ud574\uc2dc (\ubcf5\ud638\ud654 \ubd88\uac00, \uc778\uc99d\u00b7\uace0\uc720\uc131 \uc870\ud68c\uc6a9)<\/li>\n\n\n\n<li><strong>employee_no_plain<\/strong>: Fernet \uc554\ud638\ud654 (\ud45c\uc2dc\uc6a9, \ubcf5\ud638\ud654 \uac00\ub2a5)<\/li>\n\n\n\n<li><strong>name<\/strong>: Fernet \uc554\ud638\ud654 (\ud45c\uc2dc\uc6a9)<\/li>\n\n\n\n<li><strong>password<\/strong>: Django \uae30\ubcf8 PBKDF2-SHA256 \ub2e8\ubc29\ud5a5 \ud574\uc2dc<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\uc774\ub807\uac8c \ud558\uba74 DB\uac00 \uc720\ucd9c\ub418\uc5b4\ub3c4 \ud0a4 \uc5c6\uc774\ub294 \uc5b4\ub5a4 \uc815\ubcf4\ub3c4 \ubcf5\uad6c\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n<style>.kb-image6436_899054-02 .kb-image-has-overlay:after{opacity:0.3;}<\/style>\n<div class=\"wp-block-kadence-image kb-image6436_899054-02\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"600\" height=\"400\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-1-600x400.jpg\" alt=\"Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654 \uc2dc\uc2a4\ud15c \uc544\ud0a4\ud14d\ucc98 \ud504\ub85c\uc81d\ud2b8 HMAC Fernet\" class=\"kb-img wp-image-6438\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-1-600x400.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-1-300x200.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-1-768x512.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-1-18x12.jpg 18w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-1.jpg 1200w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">2. Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654 \ud575\uc2ec \uc804\ub7b5 \uc0c1\uc138 \ube44\uad50<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\ud544\ub4dc<\/th><th>\uc800\uc7a5 \ubc29\uc2dd<\/th><th>\uc6a9\ub3c4<\/th><th>\ubcf5\ud638\ud654 \uac00\ub2a5?<\/th><\/tr><\/thead><tbody><tr><td>employee_no<\/td><td>HMAC-SHA256 \ud574\uc2dc<\/td><td>\ub85c\uadf8\uc778\u00b7\uc870\ud68c<\/td><td>\ubd88\uac00<\/td><\/tr><tr><td>employee_no_plain<\/td><td>Fernet \uc554\ud638\ubb38<\/td><td>\uad00\ub9ac\uc790 \ud654\uba74 \ud45c\uc2dc<\/td><td>\uac00\ub2a5<\/td><\/tr><tr><td>name<\/td><td>Fernet \uc554\ud638\ubb38<\/td><td>\ud45c\uc2dc\u00b7\uac80\uc0c9<\/td><td>\uac00\ub2a5<\/td><\/tr><tr><td>password<\/td><td>PBKDF2-SHA256<\/td><td>\ub85c\uadf8\uc778 \uc778\uc99d<\/td><td>\ubd88\uac00<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654<\/strong>\uc758 \ud575\uc2ec\uc740 \u201c<strong>\uc870\ud68c\uc6a9\uc740 \ud574\uc2dc, \ud45c\uc2dc\uc6a9\uc740 \ub300\uce6d \uc554\ud638\ud654<\/strong>\u201d\ub97c \ubd84\ub9ac\ud558\ub294 \uac83\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. HMAC-SHA256 \uad6c\ud604 (employee_no \ubcf4\ud638)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code># apps\/accounts\/encryption.py\n# HMAC-SHA256\uc744 \uc774\uc6a9\ud55c employee_no \ud574\uc2dc \uc0dd\uc131 \ud568\uc218\n# \ubaa9\uc801: \uc0ac\ubc88\uc744 \ud3c9\ubb38\uc73c\ub85c DB\uc5d0 \uc800\uc7a5\ud558\uc9c0 \uc54a\uace0 \ub2e8\ubc29\ud5a5 \ud574\uc2dc\ub85c \uc800\uc7a5\n#       \u2192 DB\uac00 \uc720\ucd9c\ub418\uc5b4\ub3c4 \uc6d0\ubcf8 \uc0ac\ubc88\uc744 \ubcf5\uad6c\ud560 \uc218 \uc5c6\ub3c4\ub85d \ubcf4\uc548 \uac15\ud654\n\nimport hashlib\nimport hmac as _hmac\nfrom django.conf import settings\n\n\ndef hmac_of(value: str) -> str:\n    \"\"\"\n    \uc785\ub825\ub41c \ud3c9\ubb38 \uc0ac\ubc88\uc744 HMAC-SHA256 \ud574\uc2dc\ub85c \ubcc0\ud658\ud558\uc5ec \ubc18\ud658\ud569\ub2c8\ub2e4.\n    \n    - KEY: settings.FIELD_HMAC_KEY (\ud658\uacbd\ubcc0\uc218\ub85c \uad00\ub9ac, Git\uc5d0 \uc808\ub300 \ucee4\ubc0b \uae08\uc9c0)\n    - \ubcf5\ud638\ud654\uac00 \ubd88\uac00\ub2a5\ud55c \ub2e8\ubc29\ud5a5 \ud574\uc2dc \u2192 \ub85c\uadf8\uc778 \uc2dc \uc870\ud68c\uc6a9\uc73c\ub85c\ub9cc \uc0ac\uc6a9\n    - \ub3d9\uc77c\ud55c \uc0ac\ubc88\uc740 \ud56d\uc0c1 \ub3d9\uc77c\ud55c \ud574\uc2dc\uac12\uc774 \uc0dd\uc131\ub418\uc5b4 \uc911\ubcf5 \uac00\uc785 \ubc29\uc9c0\n    \"\"\"\n    # \uc124\uc815\uc5d0\uc11c HMAC \ud0a4\ub97c \uac00\uc838\uc634 (str \ub610\ub294 bytes \ubaa8\ub450 \uc9c0\uc6d0)\n    key = settings.FIELD_HMAC_KEY\n    \n    return _hmac.new(\n        key.encode() if isinstance(key, str) else key,   # \ud0a4\ub97c bytes\ub85c \ubcc0\ud658\n        value.encode(),                                  # \uc785\ub825 \uc0ac\ubc88\uc744 bytes\ub85c \ubcc0\ud658\n        hashlib.sha256                                   # SHA256 \uc54c\uace0\ub9ac\uc998 \uc0ac\uc6a9\n    ).hexdigest()                                        # 64\uc790\ub9ac hex \ubb38\uc790\uc5f4\ub85c \ubc18\ud658<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\ud68c\uc6d0\uac00\uc785 \uc2dc <code>employee_no = hmac_of(plain_no)<\/code>\ub85c \uc800\uc7a5\ud574 <strong>\ubcf5\ud638\ud654 \ubd88\uac00\ub2a5<\/strong>\ud558\uac8c \ub9cc\ub4ed\ub2c8\ub2e4.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Fernet \uc554\ud638\ud654 + Custom EncryptedCharField (\uac00\uc7a5 \uac15\ub825\ud55c Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654 \uae30\ubc95)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code># apps\/accounts\/fields.py\n# Fernet \uc554\ud638\ud654\ub97c Django \ubaa8\ub378 \ud544\ub4dc\uc5d0\uc11c \ud22c\uba85\ud558\uac8c \uc0ac\uc6a9\ud560 \uc218 \uc788\uac8c \ud574\uc8fc\ub294 \ucee4\uc2a4\ud140 \ud544\ub4dc\n# \ud2b9\uc9d5: \ubaa8\ub378 \ucf54\ub4dc\uc5d0\uc11c\ub294 \ud3c9\ubb38\ucc98\ub7fc \uc0ac\uc6a9\ud574\ub3c4 DB\uc5d0\ub294 \uc790\ub3d9\uc73c\ub85c \uc554\ud638\ubb38\uc774 \uc800\uc7a5\ub428\n\nfrom django.db import models\nfrom .encryption import encrypt_value, decrypt_value\n\n\nclass EncryptedCharField(models.TextField):\n    \"\"\"\n    Django\uc5d0\uc11c \uac1c\uc778\uc815\ubcf4(\uc774\ub984, \uc0ac\ubc88 \ud3c9\ubb38 \ub4f1)\ub97c Fernet\uc73c\ub85c \uc554\ud638\ud654\ud574\uc11c \uc800\uc7a5\ud558\ub294 \ucee4\uc2a4\ud140 \ud544\ub4dc\n    \n    - DB\uc5d0\ub294 \uc554\ud638\ubb38(ciphertext)\ub9cc \uc800\uc7a5\n    - Python \ucf54\ub4dc\uc5d0\uc11c\ub294 \ud3c9\ubb38(plaintext)\uc73c\ub85c \uc790\ub3d9 \ubcc0\ud658\ub418\uc5b4 \uc0ac\uc6a9 \uac00\ub2a5\n    - NSCG \uc900\uc218\uc5d0 \ud544\uc218\uc801\uc778 \ud22c\uba85 \uc554\ud638\ud654(Transparent Encryption) \uad6c\ud604\n    \"\"\"\n\n    def from_db_value(self, value, expression, connection):\n        \"\"\"\n        DB\uc5d0\uc11c \ub370\uc774\ud130\ub97c \uc77d\uc5b4\uc62c \ub54c \uc790\ub3d9\uc73c\ub85c \ubcf5\ud638\ud654\ud558\ub294 \uba54\uc11c\ub4dc\n        - value: DB\uc5d0 \uc800\uc7a5\ub41c \uc554\ud638\ubb38\n        - decrypt_value() \ud638\ucd9c \u2192 \ud3c9\ubb38 \ubc18\ud658\n        \"\"\"\n        return decrypt_value(value) if value is not None else value\n\n    def get_prep_value(self, value):\n        \"\"\"\n        DB\uc5d0 \uc800\uc7a5\ud558\uae30 \uc9c1\uc804\uc5d0 \uc790\ub3d9\uc73c\ub85c \uc554\ud638\ud654\ud558\ub294 \uba54\uc11c\ub4dc\n        - value: \ubaa8\ub378\uc5d0\uc11c \uc785\ub825\ub41c \ud3c9\ubb38\n        - encrypt_value() \ud638\ucd9c \u2192 \uc554\ud638\ubb38\uc73c\ub85c \ubcc0\ud658 \ud6c4 DB\uc5d0 \uc800\uc7a5\n        \"\"\"\n        if value is None or value == '':\n            return value\n        return encrypt_value(value)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654<\/strong>\uc758 \ud575\uc2ec Custom Field\uc785\ub2c8\ub2e4. \ubaa8\ub378\uc5d0\uc11c \ud3c9\ubb38\ucc98\ub7fc \uc0ac\uc6a9\ud574\ub3c4 DB\uc5d0\ub294 \uc790\ub3d9 \uc554\ud638\ubb38\uc774 \uc800\uc7a5\ub429\ub2c8\ub2e4.<\/p>\n\n\n<style>.kb-image6436_4c2174-df .kb-image-has-overlay:after{opacity:0.3;}<\/style>\n<div class=\"wp-block-kadence-image kb-image6436_4c2174-df\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"600\" height=\"894\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-600x894.jpg\" alt=\"Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654 Custom EncryptedCharField \ucf54\ub4dc KARIS\" class=\"kb-img wp-image-6437\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-600x894.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-300x447.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-768x1144.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-8x12.jpg 8w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image.jpg 784w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">5. encryption.py \uc804\uccb4 \uc720\ud2f8\ub9ac\ud2f0 (\uc2e4\uc804 \ucf54\ub4dc)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code># apps\/accounts\/encryption.py\n# Fernet (AES-128 \uae30\ubc18) \ub300\uce6d \uc554\ud638\ud654 \uad00\ub828 \ud575\uc2ec \uc720\ud2f8\ub9ac\ud2f0 \ubaa8\uc74c\n# \ubaa8\ub4e0 \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654\u00b7\ubcf5\ud638\ud654 \uc791\uc5c5\uc740 \uc774 \ud30c\uc77c\uc744 \ud1b5\ud574 \uc911\uc559 \uc9d1\uc911 \uad00\ub9ac\n\nfrom cryptography.fernet import Fernet, InvalidToken\nfrom django.conf import settings\n\n\ndef _fernet() -> Fernet:\n    \"\"\"\n    Fernet \uc778\uc2a4\ud134\uc2a4\ub97c \uc0dd\uc131\ud558\ub294 \ub0b4\ubd80 \ud5ec\ud37c \ud568\uc218\n    - settings.FIELD_ENCRYPTION_KEY\ub97c \uc0ac\uc6a9\ud574 Fernet \uac1d\uccb4 \uc0dd\uc131\n    - \ub9e4\ubc88 \uc0c8\ub85c \uc0dd\uc131\ud558\uc9c0 \uc54a\uace0 \ud544\uc694\ud560 \ub54c\ub9c8\ub2e4 \ud638\ucd9c (\uc131\ub2a5\uacfc \ubcf4\uc548 \uade0\ud615)\n    \"\"\"\n    key = settings.FIELD_ENCRYPTION_KEY\n    # \ud0a4\uac00 str\uc774\uba74 bytes\ub85c \ubcc0\ud658 (Fernet\uc740 bytes \ud0a4\ub9cc \ud5c8\uc6a9)\n    return Fernet(key.encode() if isinstance(key, str) else key)\n\n\ndef encrypt_value(plain: str) -> str:\n    \"\"\"\n    \ud3c9\ubb38 \ub370\uc774\ud130\ub97c Fernet\uc73c\ub85c \uc554\ud638\ud654\ud558\uc5ec \ubc18\ud658\n    - \ube48 \ubb38\uc790\uc5f4\uc774\ub098 None\uc740 \uadf8\ub300\ub85c \ubc18\ud658 (\uc624\ub958 \ubc29\uc9c0)\n    - \uc2e4\uc81c DB\uc5d0 \uc800\uc7a5\ub420 \uc554\ud638\ubb38 \uc0dd\uc131\n    \"\"\"\n    if not plain:\n        return plain\n    return _fernet().encrypt(plain.encode()).decode()   # bytes \u2192 str \ubcc0\ud658\n\n\ndef decrypt_value(cipher: str) -> str:\n    \"\"\"\n    Fernet \uc554\ud638\ubb38\uc744 \ubcf5\ud638\ud654\ud558\uc5ec \ud3c9\ubb38\uc73c\ub85c \ubc18\ud658\n    - InvalidToken \uc608\uc678 \ubc1c\uc0dd \uc2dc \uc6d0\ubcf8 \uc554\ud638\ubb38\uc744 \uadf8\ub300\ub85c \ubc18\ud658\n      \u2192 \ub9c8\uc774\uadf8\ub808\uc774\uc158 \uc804 \uae30\uc874 \ud3c9\ubb38 \ub370\uc774\ud130\uc640\uc758 \ud638\ud658\uc131\uc744 \uc704\ud574 \ud544\uc218\n    \"\"\"\n    if not cipher:\n        return cipher\n    try:\n        return _fernet().decrypt(cipher.encode()).decode()\n    except (InvalidToken, Exception):\n        # \ubcf5\ud638\ud654 \uc2e4\ud328 \uc2dc (\ud0a4 \ubcc0\uacbd, \ub9c8\uc774\uadf8\ub808\uc774\uc158 \uc804 \ub370\uc774\ud130 \ub4f1) \uc6d0\ubcf8 \ubc18\ud658\n        return cipher<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6. .env + settings.py \uc124\uc815 (\ud0a4 \uad00\ub9ac \ud544\uc218)<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>FIELD_ENCRYPTION_KEY=your_44char_fernet_key_here==\nFIELD_HMAC_KEY=your_64char_hex_hmac_key_here<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654<\/strong>\uc5d0\uc11c \uac00\uc7a5 \uc911\uc694\ud55c \uac83\uc740 \ud0a4\ub97c <strong>\uc808\ub300 Git\uc5d0 \ucee4\ubc0b\ud558\uc9c0 \ub9d0\uace0<\/strong> \ud658\uacbd\ubcc0\uc218 \ub610\ub294 secrets manager\uc5d0 \ubcf4\uad00\ud558\ub294 \uac83\uc785\ub2c8\ub2e4.<\/p>\n\n\n<style>.kb-image6436_0a8e56-59 .kb-image-has-overlay:after{opacity:0.3;}<\/style>\n<div class=\"wp-block-kadence-image kb-image6436_0a8e56-59\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"600\" height=\"400\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-4-600x400.jpg\" alt=\"\" class=\"kb-img wp-image-6441\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-4-600x400.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-4-300x200.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-4-768x512.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-4-18x12.jpg 18w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-4.jpg 1200w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">7. DB \uc815\uae30 \ubc31\uc5c5\ub3c4 Fernet\uc73c\ub85c \uc554\ud638\ud654 (\uc644\uc804 \ubcf4\uc548)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>python manage.py backup_db<\/code> \ucee4\ub9e8\ub4dc\ub85c MySQL\/SQLite\ub97c Fernet \uc554\ud638\ud654\ub41c <code>.enc<\/code> \ud30c\uc77c\ub85c \ubc31\uc5c5\ud569\ub2c8\ub2e4.<br>cPanel Cron\uc73c\ub85c \ub9e4\uc77c \uc0c8\ubcbd \uc790\ub3d9 \uc2e4\ud589 \u2192 <strong>DB \ubc31\uc5c5 \ud30c\uc77c\ub3c4 \uc548\uc804<\/strong>\ud569\ub2c8\ub2e4.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"600\" height=\"894\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-3-600x894.jpg\" alt=\" Django DB \ubc31\uc5c5 \uc554\ud638\ud654 \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654 \uc2dc\uc2a4\ud15c\" class=\"wp-image-6440\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-3-600x894.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-3-300x447.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-3-768x1144.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-3-8x12.jpg 8w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-3.jpg 784w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/figure>\n<\/div>\n\n\n<h4 class=\"wp-block-heading\">8. CustomUser \ubaa8\ub378\uacfc Admin \uac80\uc0c9\/\uc2b9\uc778 \uae30\ub2a5<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">CustomUser \ubaa8\ub378\uc5d0\uc11c EncryptedCharField\ub97c \uc0ac\uc6a9\ud558\uace0, Admin\uc5d0\uc11c <code>get_search_results<\/code> \uc624\ubc84\ub77c\uc774\ub4dc\ud558\uc5ec \ud3c9\ubb38 \uac80\uc0c9\uc774 \uac00\ub2a5\ud558\ub3c4\ub85d \uad6c\ud604\ud588\uc2b5\ub2c8\ub2e4.<\/p>\n\n\n<style>.kb-image6436_0e2c30-ed .kb-image-has-overlay:after{opacity:0.3;}<\/style>\n<div class=\"wp-block-kadence-image kb-image6436_0e2c30-ed\"><figure class=\"aligncenter size-large\"><img decoding=\"async\" width=\"600\" height=\"400\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-5-600x400.jpg\" alt=\"Django Admin\uc5d0\uc11c  \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654 \ud544\ub4dc \ud45c\uc2dc \ubc0f \uad00\ub9ac\" class=\"kb-img wp-image-6442\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-5-600x400.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-5-300x200.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-5-768x512.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-5-18x12.jpg 18w, https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-5.jpg 1200w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/figure><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">\uacb0\ub860: Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654\ub85c \uac1c\uc778\uc815\ubcf4\ubcf4\ud638\ubc95 \uc644\ubcbd \uc900\uc218<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654<\/strong> \uc2dc\uc2a4\ud15c\uc744 \ud504\ub85c\uc81d\ud2b8\uc5d0 \uc801\uc6a9\ud558\uba74 DB \uc720\ucd9c \uc0ac\uace0\uc5d0\ub3c4 \uac1c\uc778\uc815\ubcf4\uac00 \uc548\uc804\ud558\uac8c \ubcf4\ud638\ub429\ub2c8\ub2e4. HMAC + Fernet + Custom Field + \uc554\ud638\ud654 \ubc31\uc5c5 \uc870\ud569\uc740 \ud604\uc7ac Django\uc5d0\uc11c \uac00\uc7a5 \uc2e4\uc804\uc801\uc774\uace0 \uac15\ub825\ud55c \ubc29\ubc95\uc785\ub2c8\ub2e4.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\uc624\ub298 \ubc14\ub85c <strong>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654<\/strong>\ub97c \uc5ec\ub7ec\ubd84 \ud504\ub85c\uc81d\ud2b8\uc5d0 \ub3c4\uc785\ud574 \ubcf4\uc138\uc694. \uac1c\uc778\uc815\ubcf4\ubcf4\ud638\ubc95, GDPR \uc900\uc218\uae4c\uc9c0 \ud55c \ubc88\uc5d0 \ud574\uacb0\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\ucd9c\ucc98 \ub9ac\uc2a4\ud2b8<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Django Official Documentation: Password management and hashing (PBKDF2-SHA256)<\/li>\n\n\n\n<li>Medium: \u201cHow to Encrypt Sensitive Data with Python\/Django\u201d (Anil Kumar Valluru)<\/li>\n\n\n\n<li>Django Forum: Encryption techniques in database using Fernet (2025)<\/li>\n\n\n\n<li>GitHub: jazzband\/django-fernet-encrypted-fields \uacf5\uc2dd \uc800\uc7a5\uc18c \ubc0f \ubb38\uc11c<\/li>\n\n\n\n<li>Stack Overflow: Creating custom Django encrypted field with Fernet<\/li>\n\n\n\n<li>Medium: \u201cEncrypt Sensitive Data in Django REST APIs\u201d (Fahim Ad)<\/li>\n\n\n\n<li>Reintech: Working with File Encryption in Django<\/li>\n\n\n\n<li>Django-fernet-fields Official Docs: Field-level encryption best practices<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654\uac00 \uc65c \uc911\uc694\ud55c\uac00\uc694? \uc0ac\ubc88, \uc774\ub984 \ub4f1\uacfc \uac19\uc740 \ubbfc\uac10&#8230;<\/p>","protected":false},"author":3,"featured_media":6438,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"categories":[3],"tags":[1556,1560,1559,1554,1551,1553,1555,1557,1552,1558],"class_list":["post-6436","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python-coding","tag-django-custom-field","tag-django-db-backup-encryption","tag-django-fernet","tag-django-security","tag-django--","tag-encryptedcharfield","tag-fernet-encryption","tag-hmac-sha256","tag-karis--","tag-nscg"],"taxonomy_info":{"category":[{"value":3,"label":"\ud30c\uc774\uc36c(Python)"}],"post_tag":[{"value":1556,"label":"Django Custom Field"},{"value":1560,"label":"Django DB backup encryption"},{"value":1559,"label":"Django Fernet"},{"value":1554,"label":"Django security"},{"value":1551,"label":"Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654"},{"value":1553,"label":"EncryptedCharField"},{"value":1555,"label":"Fernet encryption"},{"value":1557,"label":"HMAC-SHA256"},{"value":1552,"label":"KARIS \uc554\ud638\ud654 \uc2dc\uc2a4\ud15c"},{"value":1558,"label":"NSCG"}]},"featured_image_src_large":["https:\/\/secondlife.lol\/wp-content\/uploads\/2026\/06\/image-1-600x400.jpg",600,400,true],"author_info":{"display_name":"TERE","author_link":"https:\/\/secondlife.lol\/ja\/author\/tere\/"},"comment_info":0,"category_info":[{"term_id":3,"name":"\ud30c\uc774\uc36c(Python)","slug":"python-coding","term_group":0,"term_taxonomy_id":3,"taxonomy":"category","description":"","parent":20,"count":118,"filter":"raw","cat_ID":3,"category_count":118,"category_description":"","cat_name":"\ud30c\uc774\uc36c(Python)","category_nicename":"python-coding","category_parent":20}],"tag_info":[{"term_id":1556,"name":"Django Custom Field","slug":"django-custom-field","term_group":0,"term_taxonomy_id":1556,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1560,"name":"Django DB backup encryption","slug":"django-db-backup-encryption","term_group":0,"term_taxonomy_id":1560,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1559,"name":"Django Fernet","slug":"django-fernet","term_group":0,"term_taxonomy_id":1559,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1554,"name":"Django security","slug":"django-security","term_group":0,"term_taxonomy_id":1554,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1551,"name":"Django \uac1c\uc778\uc815\ubcf4 \uc554\ud638\ud654","slug":"django-%ea%b0%9c%ec%9d%b8%ec%a0%95%eb%b3%b4-%ec%95%94%ed%98%b8%ed%99%94","term_group":0,"term_taxonomy_id":1551,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1553,"name":"EncryptedCharField","slug":"encryptedcharfield","term_group":0,"term_taxonomy_id":1553,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1555,"name":"Fernet encryption","slug":"fernet-encryption","term_group":0,"term_taxonomy_id":1555,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1557,"name":"HMAC-SHA256","slug":"hmac-sha256","term_group":0,"term_taxonomy_id":1557,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1552,"name":"KARIS \uc554\ud638\ud654 \uc2dc\uc2a4\ud15c","slug":"karis-%ec%95%94%ed%98%b8%ed%99%94-%ec%8b%9c%ec%8a%a4%ed%85%9c","term_group":0,"term_taxonomy_id":1552,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":1558,"name":"NSCG","slug":"nscg","term_group":0,"term_taxonomy_id":1558,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"}],"_links":{"self":[{"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/posts\/6436","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/comments?post=6436"}],"version-history":[{"count":1,"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/posts\/6436\/revisions"}],"predecessor-version":[{"id":6443,"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/posts\/6436\/revisions\/6443"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/media\/6438"}],"wp:attachment":[{"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/media?parent=6436"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/categories?post=6436"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secondlife.lol\/ja\/wp-json\/wp\/v2\/tags?post=6436"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}