在 Web 應用程式開發中,安全性是至關重要的環節。Django 作為一個成熟的 Python Web 框架,提供了 robust 的密碼雜湊和授權機制,以保護使用者資料和應用程式安全。本文將深入探討 Django 中的密碼雜湊和授權機制,並提供實務上的最佳做法。首先,我們會探討 PBKDF2 和 Argon2 等密碼雜湊演算法的應用,以及如何自訂密碼雜湊器,以滿足特定的安全需求。接著,我們將討論如何在不停機的情況下,將舊的密碼雜湊演算法遷移到新的、更安全的演算法,例如從 MD5 遷移到 Argon2。最後,我們將探討 Django 內建的授權和存取控制機制,以及如何根據需求進行自訂組態,以提升 Web 應用程式的安全性。

PBKDF2 演算法

PBKDF2(Password-Based Key Derivation Function 2)是一種常用的密碼雜湊演算法。它的主要目的是將明文密碼轉換為一串固定長度的雜湊值。PBKDF2 演算法的主要引數包括:

  • password:明文密碼
  • salt:隨機生成的 salt 值
  • iterations:迭代次數
  • key_length:雜湊值的長度

PBKDF2 演算法的基本流程如下:

  1. 將明文密碼和 salt 值進行結合,生成一個新的字串。
  2. 對新的字串進行雜湊,生成一串雜湊值。
  3. 對雜湊值進行迭代,直到達到指定的迭代次數。
  4. 對最終的雜湊值進行擷取,生成固定長度的雜湊值。

時間複雜度

時間複雜度是指演算法的執行時間與輸入大小之間的關係。在密碼雜湊中,時間複雜度是一個重要的因素,因為它直接影響了演算法的安全性。

一般來說,密碼雜湊演算法的時間複雜度應該盡可能高,以防止攻擊者使用暴力破解的方法進行攻擊。PBKDF2 演算法的時間複雜度主要取決於迭代次數和雜湊函式的選擇。

實驗結果

下面是使用 Python 實作的 PBKDF2 演算法的實驗結果:

import hashlib
import time

def pbkdf2(password, salt, iterations, key_length):
    # 將明文密碼和 salt 值進行結合
    combined = password + salt
    
    # 對新的字串進行雜湊
    hash_value = hashlib.sha256(combined.encode()).digest()
    
    # 對雜湊值進行迭代
    for _ in range(iterations):
        hash_value = hashlib.sha256(hash_value).digest()
    
    # 對最終的雜湊值進行擷取
    return hash_value[:key_length]

# 實驗引數
password = "password"
salt = "salt"
iterations = 2600000
key_length = 32

# 執行時間測量
start_time = time.time()
hash_value = pbkdf2(password, salt, iterations, key_length)
end_time = time.time()

# 執行時間輸出
print("執行時間:", end_time - start_time)

實驗結果顯示,當迭代次數增加到 2600000 時,執行時間大幅增加。這表明 PBKDF2 演算法的時間複雜度與迭代次數有直接關係。

圖表翻譯:
  flowchart TD
    A[開始] --> B[密碼雜湊]
    B --> C[PBKDF2演算法]
    C --> D[時間複雜度]
    D --> E[實驗結果]
    E --> F[結論]

這個流程圖描述了密碼雜湊的基本流程,從開始到結論,包括密碼雜湊、PBKDF2 演算法、時間複雜度和實驗結果等步驟。

密碼雜湊和安全性

當使用者登入Django專案時,需要等待PBKDF2傳回一次。如果攻擊者嘗試破解使用者的密碼,則需要等待多次,直到生成使用者的密碼。這個過程可能需要比攻擊者有時間的更長時間,如果使用者選擇了一個強大的密碼。

攻擊者通常使用圖形處理單元(GPU)來減少暴力破解攻擊的時間。GPU是為了渲染圖形而設計的專用處理器。像CPU一樣,GPU使用多個核心處理資料。CPU核心比GPU核心快,但GPU可以有更多的核心。這使得GPU在可以分割為多個可平行化子任務的任務中表現出色。這些任務包括機器學習、比特幣挖礦和密碼破解。

為了應對這個威脅,密碼學家們已經做出了反應。在2013年,一組密碼學家和安全實踐者宣佈了一個新的密碼雜湊競賽(PHC)。其目的是選擇和標準化一個能夠抵禦現代破解技術的密碼雜湊演算法。Argon2贏得了這個競賽。

Argon2既是記憶密集型也是計算密集型的。這意味著攻擊者需要獲得大量的記憶體和計算資源。Argon2因其能夠抵禦FPGA和GPU驅動的破解努力而受到讚譽。

Argon2的核心是BLAKE2。這是很有趣的,因為Argon2以其慢速而聞名。BLAKE2是一個以速度著稱的雜湊函式。

組態密碼雜湊

Django的密碼雜湊是高度可擴充套件的。這種行為是透過設定模組組態的。PASSWORD_HASHERS設定是一個密碼雜湊器的列表。

預設值是一個包含四個密碼雜湊器實作的列表。每個密碼雜湊器都包裝了一個KDF。前三個應該看起來很熟悉:

PASSWORD_HASHERS = [
    # ...
]

Django使用列表中的第一個密碼雜湊器對新密碼進行雜湊。這發生在您的帳戶建立和密碼更改時。雜湊值儲存在資料函式庫中,可以用於驗證未來的身份驗證嘗試。

列表中的任何密碼雜湊器都可以驗證身份驗證嘗試對已經儲存的雜湊值。例如,一個組態了前面示例的專案將使用PBKDF2對新密碼或更改的密碼進行雜湊,但它可以驗證之前由Argon2或BCryptSHA256雜湊的密碼。

每次使用者成功登入時,Django都會檢查使用者的密碼是否使用列表中的第一個密碼雜湊器進行了雜湊。如果沒有,則密碼會使用第一個密碼雜湊器重新雜湊,然後雜湊值會儲存在資料函式庫中。

本地密碼雜湊器

Django本地支援10個密碼雜湊器。MD5PasswordHasher、SHA1PasswordHasher和它們的非加鹽版本是不安全的。這些元件以粗體顯示。Django為了與舊系統的向後相容而維護這些密碼雜湊器:

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]

圖表翻譯:

  flowchart TD
    A[使用者登入] --> B[密碼雜湊]
    B --> C[驗證]
    C --> D[授權]
    D --> E[儲存]

在這個圖表中,我們可以看到使用者登入的流程。使用者的密碼會被雜湊,然後驗證。如果驗證成功,則授權使用者儲存其資料。

密碼雜湊器的選擇和自訂

在 Django 中,密碼雜湊器(Password Hasher)是一個非常重要的安全元件,負責將使用者的密碼轉換為安全的雜湊值,以保護使用者的密碼安全。Django 提供了多種密碼雜湊器,包括 PBKDF2PasswordHasherSHA1PasswordHasherMD5PasswordHasher 等。

預設密碼雜湊器

Django 預設使用 PBKDF2PasswordHasher,這是一種安全且廣泛使用的密碼雜湊器。PBKDF2PasswordHasher 使用 PBKDF2 演算法,該演算法是一種根據密碼的金鑰匯出函式(Password-Based Key Derivation Function),可以將密碼轉換為安全的金鑰。

自訂密碼雜湊器

如果您想要增加密碼雜湊器的安全性,可以自訂一個密碼雜湊器。例如,以下是一個自訂的密碼雜湊器,名為 TwoFoldPBKDF2PasswordHasher,它繼承自 PBKDF2PasswordHasher 並將迭代次數增加一倍:

class TwoFoldPBKDF2PasswordHasher(PBKDF2PasswordHasher):
    iterations = PBKDF2PasswordHasher.iterations * 2

這個自訂密碼雜湊器將迭代次數增加一倍,這可以提高密碼雜湊器的安全性,但也會增加登入的延遲時間。

不安全的密碼雜湊器

有一些密碼雜湊器是不安全的,例如 SHA1PasswordHasherMD5PasswordHasher。這些密碼雜湊器使用的演算法是快速且不安全的,容易被攻擊者破解。因此,應該避免使用這些密碼雜湊器。

圖表翻譯:

  flowchart TD
    A[密碼] --> B[密碼雜湊器]
    B --> C[安全的雜湊值]
    C --> D[儲存]
    D --> E[驗證]
    E --> F[授權]

這個圖表展示了密碼雜湊器的工作流程,從密碼輸入到安全的雜湊值儲存和驗證。

密碼雜湊組態

在 Django 中,密碼雜湊是一個重要的安全機制,負責保護使用者的密碼不被輕易破解。為了確保密碼的安全性,Django 提供了多種密碼雜湊演算法,包括 PBKDF2、Argon2 等。

自定義密碼雜湊器

要使用自定義的密碼雜湊器,需要在 PASSWORD_HASHERS 設定中指定自定義的雜湊器類別。例如:

PASSWORD_HASHERS = [
    'profile_info.hashers.TwoFoldPBKDF2PasswordHasher',
]

這裡,TwoFoldPBKDF2PasswordHasher 是一個自定義的密碼雜湊器類別,負責處理密碼的雜湊和驗證。

Argon2 密碼雜湊

Argon2 是一個高安全性的密碼雜湊演算法,目前被廣泛使用。要在 Django 中使用 Argon2,需要先安裝 argon2-cffi 套件:

$ pipenv install django[argon2]

然後,在 PASSWORD_HASHERS 設定中指定 Argon2 密碼雜湊器:

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',
]

注意:如果系統已經在生產環境中使用,則不應直接替換所有密碼雜湊器為 Argon2 密碼雜湊器。這樣做會導致現有使用者無法登入。相反,應該將 Argon2 密碼雜湊器放在 PASSWORD_HASHERS 的首位,然後保留舊的密碼雜湊器作為備用。

密碼雜湊器遷移

當系統已經在生產環境中使用時,遷移所有使用者到新的密碼雜湊器可能是一個挑戰。Django 只有在使用者登入時才會升級現有的密碼雜湊值。這意味著,如果使用者不登入,則其密碼雜湊值將保持不變,可能會導致安全性問題。

圖表翻譯:

  flowchart TD
    A[使用者登入] --> B[密碼雜湊器驗證]
    B --> C[密碼雜湊值升級]
    C --> D[新密碼雜湊器儲存]
    D --> E[使用者資料更新]

在這個流程中,當使用者登入時,密碼雜湊器會驗證其密碼,並升級現有的密碼雜湊值。然後,新密碼雜湊器會儲存升級後的密碼雜湊值,最後更新使用者資料。

內容解密:

在這個過程中,Django 使用 Argon2 密碼雜湊器來保護使用者的密碼。當使用者登入時,Argon2 密碼雜湊器會驗證其密碼,並升級現有的密碼雜湊值。這樣可以確保使用者的密碼安全性,同時也可以遷移所有使用者到新的密碼雜湊器。

密碼雜湊遷移

2012 年 6 月,LinkedIn 的資料外洩事件被宣佈的同一周,超過 150 萬個 eharmony 密碼的未加鹽雜湊值被洩露並發布。這些雜湊值被儲存在一個名為 hashes.txt 的檔案中。當時,eharmony 使用 MD5 這種不安全的雜湊函式來處理密碼。

如果 eharmony 對其雜湊值使用了鹽,就像它應該做的那樣,我就不會能夠執行這種攻擊。事實上,使用鹽會強制我對每個雜湊值執行字典攻擊,這將需要我超過 31 年的時間。

讓我們考慮一下 eharmony 如何能夠減輕這個問題。假設這是 Alice 在 eharmony 的第一天工作。她繼承了一個現有的系統,具有以下組態:

PASSWORD_HASHERS = [
    # UnsaltedMD5PasswordHasher
]

這個系統的作者因為使用 UnsaltedMD5PasswordHasher 而被解僱。現在,Alice 負責將系統遷移至 Argon2PasswordHasher,而不會有任何停機時間。系統有 150 萬使用者,因此她不能強制所有使用者再次登入。產品經理不希望重置每個帳戶的密碼,這是可以理解的。Alice 意識到,她唯一的選擇是對密碼進行兩次雜湊,一次使用 UnsaltedMD5PasswordHasher,另一次使用 Argon2PasswordHasher。Alice 的計畫是新增、遷移、刪除:

  1. 新增 Argon2PasswordHasher
  2. 遷移雜湊值
  3. 刪除 UnsaltedMD5PasswordHasher

首先,Alice 將 Argon2PasswordHasher 新增到 PASSWORD_HASHERS 列表中。這限制了問題的範圍,僅限於最近未登入的現有使用者。引入 Argon2PasswordHasher 是容易的部分;刪除 UnsaltedMD5PasswordHasher 是困難的部分。Alice 保留 UnsaltedMD5PasswordHasher 在列表中,以確保現有使用者可以存取其帳戶:

PASSWORD_HASHERS = [
    'Argon2PasswordHasher',  # 新增 Argon2PasswordHasher
    'UnsaltedMD5PasswordHasher',  # 保留 UnsaltedMD5PasswordHasher
]

接下來,Alice 必須遷移雜湊值;這是大部分的工作。她不能簡單地使用 Argon2 重新雜湊密碼,因此她必須使用雙重雜湊。換句話說,她計劃從資料函式庫中讀取每個 MD5 雜湊值並將其傳遞給 Argon2Argon2 的輸出將是另一個雜湊值,然後將替換原始雜湊值在資料函式庫中。Argon2 需要鹽,並且比 MD5 慢得多;這意味著對於像 Mallory 這樣的攻擊者來說,破解這些密碼需要超過 31 年的時間。

內容解密:

在這個過程中,Alice 需要小心地遷移雜湊值,以確保使用者可以繼續登入。這個過程涉及到對密碼進行雙重雜湊,一次使用 UnsaltedMD5PasswordHasher,另一次使用 Argon2PasswordHasher。這樣可以確保現有使用者可以存取其帳戶,並且新的雜湊值更加安全。

圖表翻譯:

以下是 Alice 的遷移計畫的視覺化表示:

  flowchart TD
    A[開始] --> B[新增 Argon2PasswordHasher]
    B --> C[遷移雜湊值]
    C --> D[刪除 UnsaltedMD5PasswordHasher]
    D --> E[完成遷移]

這個流程圖表明了 Alice 的遷移計畫的步驟,從新增 Argon2PasswordHasher 到刪除 UnsaltedMD5PasswordHasher。每一步驟都需要小心地執行,以確保使用者可以繼續登入,並且新的雜湊值更加安全。

密碼雜湊演算法升級

在網路安全中,密碼雜湊演算法的選擇對於保護使用者密碼的安全性至關重要。隨著技術的進步,舊的密碼雜湊演算法可能會被發現有安全漏洞,因此需要升級到更安全的演算法。

Argon2PasswordHasher 和 UnsaltedMD5PasswordHasher

Argon2PasswordHasher 是一種安全的密碼雜湊演算法,它使用 Argon2 演算法來保護密碼。UnsaltedMD5PasswordHasher 是一種較舊的密碼雜湊演算法,它使用 MD5 演算法來保護密碼。然而,MD5 演算法已經被發現有安全漏洞,因此需要升級到更安全的演算法。

自訂密碼雜湊演算法

為了升級密碼雜湊演算法,需要建立一個自訂的密碼雜湊演算法,它可以橋接 Argon2PasswordHasher 和 UnsaltedMD5PasswordHasher 之間的差距。這個自訂的密碼雜湊演算法需要實作兩個方法:encodeverify

encode 方法

encode 方法被用於當使用者密碼被設定時,它需要將密碼進行雜湊並傳回雜湊值。這個方法需要使用 MD5 演算法來雜湊密碼,並將雜湊值儲存在資料函式庫中。

verify 方法

verify 方法被用於當使用者登入時,它需要比較原來的雜湊值和重製密碼的雜湊值。如果兩個雜湊值相同,則使用者密碼是正確的。

實作自訂密碼雜湊演算法

以下是自訂密碼雜湊演算法的實作:

from django.contrib.auth.hashers import Argon2PasswordHasher, UnsaltedMD5PasswordHasher

class UnsaltedMD5ToArgon2PasswordHasher(Argon2PasswordHasher):
    algorithm = '%s->%s' % (UnsaltedMD5PasswordHasher.algorithm, Argon2PasswordHasher.algorithm)

    def encode(self, password, salt):
        md5_hash = self.get_md5_hash(password)
        return self.encode_md5_hash(md5_hash, salt)

    def verify(self, password, encoded):
        md5_hash = self.get_md5_hash(password)
        return super().verify(md5_hash, encoded)

    def encode_md5_hash(self, md5_hash, salt):
        return super().encode(md5_hash, salt)

    def get_md5_hash(self, password):
        hasher = UnsaltedMD5PasswordHasher()
        return hasher.encode(password, hasher.salt())

組態自訂密碼雜湊演算法

為了使用自訂密碼雜湊演算法,需要在 PASSWORD_HASHERS 設定中新增自訂的密碼雜湊演算法。

PASSWORD_HASHERS = [
    'path.to.UnsaltedMD5ToArgon2PasswordHasher',
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
]

透過這種方式,可以升級密碼雜湊演算法,提高使用者密碼的安全性。

雙重雜湊過程的實作

為了提高密碼儲存的安全性,Alice 決定使用雙重雜湊的方法。首先,她需要修改 Django 的設定,使用 UnsaltedMD5ToArgon2PasswordHasher 雜湊器。這個雜湊器可以將 MD5 雜湊值重新雜湊為 Argon2 雜湊值。

PASSWORD_HASHERS = [
    'django_app.hashers.UnsaltedMD5ToArgon2PasswordHasher',
]

接下來,Alice 需要建立一個 Django 遷移,修改現有的 MD5 雜湊值為 Argon2 雜湊值。這個過程需要使用 Django 的 migrations 框架。

from django.db import migrations
from django.db.models.functions import Length
from django_app.hashers import UnsaltedMD5ToArgon2PasswordHasher

def forwards_func(apps, schema_editor):
    User = apps.get_model('auth', 'User')
    unmigrated_users = User.objects.annotate(
        text_len=Length('password')).filter(text_len=32)
    hasher = UnsaltedMD5ToArgon2PasswordHasher()

    for user in unmigrated_users:
        md5_hash = user.password
        salt = hasher.salt()
        user.password = hasher.encode_md5_hash(md5_hash, salt)
        user.save(update_fields=['password'])

class Migration(migrations.Migration):
    dependencies = [
        ('auth', '0011_update_proxy_permissions'),
    ]

    operations = [
        migrations.RunPython(forwards_func),
    ]

在這個過程中,Alice 使用 UnsaltedMD5ToArgon2PasswordHasher 雜湊器將每個 MD5 雜湊值重新雜湊為 Argon2 雜湊值。然後,她將新的 Argon2 雜湊值儲存回資料函式庫。

由於 Argon2 雜湊演算法相對較慢,Alice 知道這個過程可能需要一些時間。因此,她需要確保這個過程在生產環境中順暢地執行。

內容解密:

  • UnsaltedMD5ToArgon2PasswordHasher 雜湊器的作用是將 MD5 雜湊值重新雜湊為 Argon2 雜湊值。
  • forwards_func 函式是用於修改現有的 MD5 雜湊值為 Argon2 雜湊值的過程。
  • User.objects.annotate(text_len=Length('password')).filter(text_len=32) 是用於篩選出尚未被遷移的使用者。
  • hasher.encode_md5_hash(md5_hash, salt) 是用於將 MD5 雜湊值重新雜湊為 Argon2 雜湊值。

圖表翻譯:

  flowchart TD
    A[開始] --> B[篩選未遷移使用者]
    B --> C[重新雜湊 MD5 值]
    C --> D[儲存新的 Argon2 雜湊值]
    D --> E[完成]

這個流程圖描述了 Alice 如何篩選出尚未被遷移的使用者,重新雜湊 MD5 值,然後儲存新的 Argon2 雜湊值的過程。

密碼重置工作流程

在上一節中,我們討論瞭如何使用 Django 的內建檢視實作密碼修改工作流程。在這一節中,我們將探討如何使用另一個工作流程實作密碼重置。

密碼重置檢視

Django 提供了四個內建檢視來實作密碼重置工作流程:

  1. PasswordResetView:用於處理密碼重置請求的檢視。
  2. PasswordResetDoneView:用於顯示密碼重置完成的檢視。
  3. PasswordResetConfirmView:用於確認密碼重置的檢視。
  4. PasswordResetCompleteView:用於顯示密碼重置完成的檢視。

密碼重置工作流程

當使用者忘記密碼時,可以使用密碼重置工作流程來重置密碼。以下是工作流程的步驟:

  1. 使用者存取密碼重置頁面,並提交包含其電子郵件地址的表單。
  2. PasswordResetView 處理表單提交,然後傳送包含密碼重置連結的電子郵件給使用者。
  3. 使用者點選密碼重置連結,然後被導向到密碼重置頁面。
  4. PasswordResetConfirmView 處理密碼重置請求,然後確認使用者的身份。
  5. 如果確認成功,則使用者可以重置其密碼。

密碼重置令牌

密碼重置連結包含使用者的 ID 和一個密碼重置令牌。這個令牌不是一個隨機字串,而是一個使用 HMAC 函式生成的金鑰雜湊值。密碼重置檢視使用 HMAC 函式生成這個雜湊值,然後將其包含在密碼重置連結中。

密碼重置令牌的安全性

密碼重置令牌的安全性是由 HMAC 函式和金鑰確保的。HMAC 函式使用金鑰和訊息生成一個雜湊值,這個雜湊值可以用來驗證訊息的完整性和真實性。

密碼重置令牌的過期時間

密碼重置令牌有過期時間,這可以用來防止惡意使用者使用過期的密碼重置連結。過期時間可以使用 PASSWORD_RESET_TIMEOUT 設定來組態。

實作密碼重置工作流程

要實作密碼重置工作流程,需要將四個內建檢視對映到 URL 路徑上。然後,當使用者存取密碼重置頁面時,會觸發密碼重置工作流程。

from django.urls import path
from django.contrib.auth import views as auth_views

urlpatterns = [
    path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
    path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
    path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
    path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]

授權與存取控制

在前面的章節中,我們討論了認證和密碼雜湊的相關概念。在本章中,我們將深入探討授權和存取控制的世界。授權是指定義使用者可以執行哪些操作的過程,而存取控制則是實施這些授權的機制。

從系統安全性的角度來看,本文深入探討了密碼雜湊的機制、演算法選擇、以及如何安全地升級密碼雜湊演算法。PBKDF2 作為一個相對安全的密碼雜湊函式,其安全性仰賴於足夠的迭代次數和 salt 的使用,但面對現代硬體攻擊,其防禦能力已顯不足。分析 Argon2 等更安全的現代密碼雜湊演算法,突顯了其記憶體密集型設計在抵禦 GPU 破解方面的優勢。文章詳細闡述瞭如何在 Django 專案中組態和自訂密碼雜湊器,特別強調了在不停機的情況下,將舊系統從不安全的 MD5 雜湊遷移到 Argon2 的策略,並以 Alice 的案例具體說明瞭「新增、遷移、刪除」的步驟,展現了務實的解決方案。然而,僅僅升級雜湊演算法並不足以確保系統安全,完善的密碼重置機制和授權存取控制策略同等重要。未來,隨著硬體技術的持續發展,密碼雜湊演算法也需要不斷演進,以應對新的安全挑戰。對於開發者而言,持續關注密碼學的最新進展,並將其應用於系統設計中,才能有效保障使用者資訊安全。玄貓認為,採用 Argon2 等更安全的雜湊演算法,並結合多因素驗證等安全措施,是提升系統安全性的必要步驟。