Djangoにおけるパスワード管理

パスワード管理は一般的に、不必要に再発明されるべきではないものです。Djangoはユーザーのパスワードを管理するための安全で柔軟なツールセットを提供するよう努めています。このドキュメントでは、Djangoがパスワードを保存する方法、ストレージハッシュの設定方法、およびハッシュされたパスワードを扱ういくつかのユーティリティについて説明します。

参考

ユーザーが強力なパスワードを使ったとしても、攻撃者が通信経路上において盗聴をおこなう可能性があります。パスワード (または他の機密データ) がプレーンな HTTP コネクションで送信されないように、 HTTPS を使用してください。なぜなら、HTTP はパスワードスニッフィングに対して脆弱であるからです。

Djangoのパスワード保存方法

DjangoはデフォルトでPBKDF2を利用した、柔軟なパスワード保存システムを提供します。

User オブジェクトの password 属性は、次のような形式の文字列です。

<algorithm>$<iterations>$<salt>$<hash>

これらはユーザーのパスワードを保存するためのコンポーネントで、ハッシュアルゴリズム、アルゴリズムのイテレーション回数(ワークファクター)、ランダムなソルト、そして結果のパスワードハッシュをドル記号($)で区切ったものです。このアルゴリズムは、Djangoが使用できる数多くの一方向ハッシュ、またはパスワード保存アルゴリズム(下記参照)の一つです。イテレーションはハッシュに対してアルゴリズムが実行された回数を表します。ソルトは使用されたランダムシードで、ハッシュは一方向ハッシュ関数の実行結果です。

デフォルトでは、Djangoは NIST が推奨するパスワードストレッチングメカニズムである PBKDF2 アルゴリズムと SHA256 ハッシュを使用します。これはほとんどのユーザーに十分有効なはずです。非常に安全で、クラックするのに膨大な計算時間を必要とします。

ただし、要件に応じて、異なるアルゴリズムを使用することも、一部のセキュリティ状況に合わせてカスタムアルゴリズムを使用することもできます。繰り返しますが、ほとんどのユーザーはこれを行う必要はありません。よくわからない場合、おそらくそうしないほうが良いです。もしそうする場合は、こちらをお読みください:

Django は PASSWORD_HASHERS 設定を参照して、使用するアルゴリズムを選択します。これは、この Django インストールがサポートしているハッシュアルゴリズムクラスのリストです。

パスワードの保存には、 Django は PASSWORD_HASHERS の最初のハッシャーを使います。別のアルゴリズムで新しいパスワードを保存するには、 PASSWORD_HASHERS にあなたの好きなアルゴリズムを最初に書いてください。

パスワードの検証のために、 Django は保存されたパスワードのアルゴリズム名と一致するハッ シャーをリストの中から探します。保存されたパスワードが PASSWORD_HASHERS にないアルゴリズ ム名を持つ場合、それを検証しようとすると ValueError が発生します。

デフォルトでの PASSWORD_HASHERS

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

これは、Djangoは PBKDF2 を使用して全てのパスワードを保存しますが、PBKDF2SHA1、 argon2 、および bcrypt で保存されたパスワードのチェックもサポートすることを意味しています。

次のいくつかのセクションでは、高度なユーザーがこの設定を変更するための一般的な方法について説明します。

Django で Argon2 を使う

Argon2 は、次世代ハッシュアルゴリズムを選定するコミュニティ主催のオープンコンペティションである、2015年の Password Hashing Competition の優勝者です。カスタムハードウェアで計算しても、通常のCPUで計算するよりも有利にならないように設計されています。Argon2パスワードハッシュのデフォルトのバリアントはArgon2idです。

Argon2 はサードパーティのライブラリを必要とするため、 Django のデフォルトではありません。しかし、 Password Hashing Competition パネルでは、 Django がサポートしている他のアルゴリズムではなく、 Argon2 をすぐに使うことを推奨しています。

Argon2idをデフォルトのストレージアルゴリズムとして使用するには、以下のようにします:

  1. argon2-cffi パッケージをインストールしてください。これは python -m pip install django[argon2] と等価です(Django の setup.cfg に記載されたバージョン要件も含みます)。

  2. PASSWORD_HASHERS を変更して、Argon2PasswordHasher を最初にリストアップします。つまり、設定ファイルに下記のように書きます:

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

    Django に パスワードのアップグレード をさせる必要がある場合は、このリストにエントリを残すまたは追加してください。

Django で bcrypt を使う

Bcrypt は一般的なパスワード保存アルゴリズムで、特にパスワードの長期保存用に設計されています。サードパーティのライブラリを使う必要があるため、 Django がデフォルトで使うものではありませんが、多くの人が使いたいでしょうから、 Django は最小限の労力で bcrypt をサポートしています。

Bcrypt をデフォルトのストレージアルゴリズムとして使用するには、以下のようにします:

  1. bcrypt パッケージをインストールします。これは python -m pip install django[bcrypt] と等価です (Django の setup.cfg から必要なバージョンを指定してください)。

  2. PASSWORD_HASHERS を変更して、BCryptSHA256PasswordHasher を最初にリストアップします。つまり、設定ファイルに下記のように書きます:

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

    Django に パスワードのアップグレード をさせる必要がある場合は、このリストにエントリを残すまたは追加してください。

これで Django はデフォルトのストレージアルゴリズムとして Bcrypt を使うようになります。

Django で scrypt を使う

scrypt は、ブルートフォース攻撃を減速させるために設定されたイテレーション数を利用するという点で、PBKDF2やbcryptと似ています。しかし、PBKDF2とbcryptは多くのメモリを必要としないため、十分なリソースを持つ攻撃者は、攻撃プロセスを高速化するために大規模な並列攻撃を仕掛けることができます。 scrypt は、攻撃者が使用できる並列処理の量を制限するために、他のパスワードベースの鍵導出関数と比較してより多くのメモリを使用するように特別に設計されています。

scrypt をデフォルトのストレージアルゴリズムとして使用するには、以下のようにします:

  1. PASSWORD_HASHERS を変更して、ScryptPasswordHasher を最初にリストアップします。つまり、設定ファイルに下記のように書きます:

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

    Django に パスワードのアップグレード をさせる必要がある場合は、このリストにエントリを残すまたは追加してください。

注釈

scrypt はOpenSSL 1.1+を必要とします。

ソルトのエントロピーを増加させる

ほとんどのパスワードハッシュはレインボーテーブル攻撃から守るために、パスワードハッシュと一緒にソルトを含んでいます。ソルトはランダムな値であり、レインボーテーブルのサイズとコストを増加させます。現在は BasePasswordHashersalt_entropy 値で128ビットに設定されています。計算機やストレージのコストが下がれば、この値を上げる必要があります。独自のパスワードハッシュを実装する場合、パスワードハッシュに希望するエントロピーレベルを使用するために、この値を自由に上書きできます。 salt_entropy の単位はビットです。

実装の詳細

ソルト値が保存されるメカニズムにより、 salt_entropy 値は実際には最小値です。たとえば、128という値は実際には131ビットのエントロピーを含むソルトを提供します。

work factor を増やす

PBKDF2 と bcrypt

PBKDF2 と bcrypt アルゴリズムは、ハッシュ化に何度もイテレート(ラウンド)します。これは意図的に攻撃者の速度を低下させ、ハッシュ化されたパスワードに対する攻撃を困難にします。しかし、計算能力が上がるにつれて、イテレーションの回数を増やす必要があります。私たちは妥当なデフォルト値を選びました(そして Django のリリー スごとに増やす予定です)が、セキュリティの必要性や利用可能な処理能力に応じて、上げたり下げたりすることもできます。そのためには、適切なアルゴリズムをサブクラス化し、 iterations パラメータをオーバーライドします (bcrypt hasher をサブクラス化するときは rounds パラメータを使います)。たとえば、デフォルトの PBKDF2 アルゴリズムで使用するイテレーションの回数を増やすには、次のようにします:

  1. django.contrib.auth.hashers.PBKDF2PasswordHasher のサブクラスを作成します:

    from django.contrib.auth.hashers import PBKDF2PasswordHasher
    
    
    class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher):
        """
        A subclass of PBKDF2PasswordHasher that uses 100 times more iterations.
        """
    
        iterations = PBKDF2PasswordHasher.iterations * 100
    

    これをプロジェクトのどこかに保存します。たとえば、 myproject/hashers.py のようなファイルに保存します。

  2. 新しいハッシャーを PASSWORD_HASHERS の最初のエントリーとして追加します:

    PASSWORD_HASHERS = [
        "myproject.hashers.MyPBKDF2PasswordHasher",
        "django.contrib.auth.hashers.PBKDF2PasswordHasher",
        "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
        "django.contrib.auth.hashers.Argon2PasswordHasher",
        "django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
        "django.contrib.auth.hashers.ScryptPasswordHasher",
    ]
    

これで Django が PBKDF2 を使ってパスワードを保存する際に、より多くのイテレーションを使うようになります。

注釈

bcrypt の rounds は対数の work factor で、たとえば 12 ラウンドは 2 ** 12 のイテレーションを意味します。

Argon2

Argon2には、カスタマイズ可能な以下の属性があります:

  1. time_cost はハッシュ内のイテレートする回数をコントロールします。
  2. memory_cost は、ハッシュの計算に必要なメモリのサイズをコントロールします。
  3. parallelism はハッシュの計算をいくつのCPUで並列化できるかを制御します。

これらの属性のデフォルト値は、おそらく問題ないでしょう。パスワード・ハッシュが速すぎたり遅すぎたりすると判断した場合は、以下のように微調整できます:

  1. parallelism は、ハッシュを計算するスレッド数を指定します。
  2. memory_cost には、余裕を持ったメモリのKiBを選択してください。
  3. time_cost を調整し、パスワードのハッシュにかかる時間を測定します。 time_cost は、あなたにとって許容できる時間を選んでください。もし time_cost に 1 を指定しても許容できないほど遅い場合は、 memory_cost を下げてください。

memory_cost の解釈

argon2 コマンドラインユーティリティと他のいくつかのライブラリは、 memory_cost パラメータを Django が使う値とは異なる解釈をします。変換は memory_cost == 2 ** memory_cost_commandline で行います。

scrypt

scrypt にはカスタマイズ可能な以下の属性があります:

  1. work_factor はハッシュ内のイテレートする回数をコントロールします。
  2. block_size
  3. parallelism はいくつのスレッドが並列に実行されるかをコントロールします。
  4. maxmem はハッシュの計算中に使用できるメモリの最大サイズを制限します。デフォルトは 0 で、OpenSSL ライブラリによるデフォルトの制限を意味します。

私たちは合理的なデフォルト値を選びましたが、セキュリティのニーズや利用可能な処理能力に応じて、調整することもできます。

メモリ使用量の見積もり

scrypt に必要な最小のメモリサイズは以下の通りです:

work_factor * 2 * block_size * 64

そのため、 work_factorblock_size の値を変更する際には maxmem を調整する必要があるかもしれません。

パスワードのアップグレード

ユーザーがログインする際、もしそのパスワードが推奨されるアルゴリズム以外で保存されていた場合、Djangoは自動で推奨されるアルゴリズムへ更新します。つまり、Djangoの古いインストールでも、ユーザーのログイン時に自動的にセキュリティが強化され、新しい(より良い)保存アルゴリズムが開発されるたびに切り替えることができるということです。

ただし、Djangoは PASSWORD_HASHERS で定義されたアルゴリズムを使用するパスワードしか更新できません。そのため、新しいシステムにアップグレードする際には絶対にこのリストからエントリを「削除」しないでください。そうしないと、定義されてないアルゴリズムを使用するユーザーのパスワードを更新できなくなります。ハッシュされたパスワードは、PBKDF2のイテレーション回数、bcrypt のラウンド数、または argon2 の属性数を増やす (または減らす) と更新されます。

データベース上の全てのパスワードがデフォルトのハッシュアルゴリズムでエンコードされていない場合、デフォルト以外のアルゴリズムでエンコードされたパスワードを持つユーザーと、存在しないユーザー(デフォルトのハッシュアルゴリズムが実行されます)に対するログインリクエストにかかる時間の差に起因する、ユーザー列挙型タイミング攻撃に対して脆弱になる可能性があることに注意してください。 古いパスワードハッシュの更新 によりこれを軽減できます。

ログインを必要としないパスワードアップグレード

既存のデータベースが MD5 のような古くて弱いハッシュを使用している場合、ユーザがログインしたときにハッシュのアップグレードが行われるのを待つのではなく、自分でハッシュをアップグレードしたいと思うかもしれません (ユーザがサイトに戻ってこない場合は、アップグレードが行われないかもしれません)。この場合、「ラップ」パスワードハッシュを使用できます。

この例では、PBKDF2(MD5(password)) を使用するように MD5 ハッシュのコレクションをマイグレーションし、ユーザがログイン時に正しいパスワードを入力したかどうかをチェックするために、対応するパスワードハッシュを追加します。組み込みの User モデルを使用しており、プロジェクトには accounts アプリがあると仮定します。このパターンをカスタマイズすることで、任意のアルゴリズムやカスタムユーザモデルで動作させることができます。

まず、独自のハッシャーを追加します:

accounts/hashers.py
from django.contrib.auth.hashers import (
    PBKDF2PasswordHasher,
    MD5PasswordHasher,
)


class PBKDF2WrappedMD5PasswordHasher(PBKDF2PasswordHasher):
    algorithm = "pbkdf2_wrapped_md5"

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

    def encode(self, password, salt, iterations=None):
        _, _, md5_hash = MD5PasswordHasher().encode(password, salt).split("$", 2)
        return self.encode_md5_hash(md5_hash, salt, iterations)

データマイグレーションは次のようになります:

accounts/migrations/0002_migrate_md5_passwords.py
from django.db import migrations

from ..hashers import PBKDF2WrappedMD5PasswordHasher


def forwards_func(apps, schema_editor):
    User = apps.get_model("auth", "User")
    users = User.objects.filter(password__startswith="md5$")
    hasher = PBKDF2WrappedMD5PasswordHasher()
    for user in users:
        algorithm, salt, md5_hash = user.password.split("$", 2)
        user.password = hasher.encode_md5_hash(md5_hash, salt)
        user.save(update_fields=["password"])


class Migration(migrations.Migration):
    dependencies = [
        ("accounts", "0001_initial"),
        # replace this with the latest migration in contrib.auth
        ("auth", "####_migration_name"),
    ]

    operations = [
        migrations.RunPython(forwards_func),
    ]

このマイグレーションには、ハードウェアの速度にもよりますが、数千人のユーザーで数分かかることに注意してください。

最後に PASSWORD_HASHERS 設定を追加します:

mysite/settings.py
PASSWORD_HASHERS = [
    "django.contrib.auth.hashers.PBKDF2PasswordHasher",
    "accounts.hashers.PBKDF2WrappedMD5PasswordHasher",
]

あなたのサイトが使用している他のハッシャーもこのリストに含めてください。

Django に含まれるハッシャー

Django に含まれるハッシャーの全リストは以下の通りです:

[
    "django.contrib.auth.hashers.PBKDF2PasswordHasher",
    "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
    "django.contrib.auth.hashers.Argon2PasswordHasher",
    "django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
    "django.contrib.auth.hashers.BCryptPasswordHasher",
    "django.contrib.auth.hashers.ScryptPasswordHasher",
    "django.contrib.auth.hashers.MD5PasswordHasher",
]

対応するアルゴリズム名は以下の通りです:

  • pbkdf2_sha256
  • pbkdf2_sha1
  • argon2
  • bcrypt_sha256
  • bcrypt
  • scrypt
  • md5

独自のハッシャーを書く

イテレーション回数のようなワークファクターを含む独自のパスワードハッシャーを書く場合は、 harden_runtime(self, password, encoded) メソッドを実装して、 エンコードされた パスワードに指定されたワークファクターとハッシャーのデフォルトのワークファクターとの間のランタイムギャップを埋める必要があります。これにより、古いイテレーション数でエンコードされたパスワードを持つユーザーと存在しないユーザー(デフォルトのハッシャーのデフォルトのイテレーション数で実行される)のログイン要求の違いによるユーザー列挙タイミング攻撃を防ぐことができます。

PBKDF2 を例にとると、 encoded が 20,000 回のイテレーションを含み、ハッシャーのデフォルトの iterations が 30,000 回である場合、このメソッドは password を PBKDF2 のさらに 10,000 回のイテレーションに通す必要があります。

もしあなたのハッシャーがワークファクターを持っていない場合は、このメソッドを何もしない操作 (pass) として実装してください。

ユーザーのパスワードを手動で管理する

django.contrib.auth.hashers モジュールは、ハッシュ化されたパスワードを作成・検証するための関数群を提供します。これらは User モデルとは独立して使用できます。

check_password(password, encoded, setter=None, preferred='default')
acheck_password(password, encoded, asetter=None, preferred='default')

非同期バージョン: acheck_password()

もしプレーンテキストのパスワードとデータベースのハッシュ化されたパスワードを比較して手動でユーザーを認証したい場合は、 check_password() という便利な関数を使用してください。この関数は2つの必須引数を取ります。チェックするプレーンテキストのパスワードと、照合するデータベースの password フィールドの完全な値です。これらが一致すれば True を返し、一致しなければ False を返します。オプションとして、呼び出し可能な setter を渡すことができます。この setter はパスワードを受け取り、再生成の必要がある際に呼び出されます。また、デフォルトのハッシュアルゴリズム (PASSWORD_HASHERS 設定の最初のエントリ) を使用したくない場合は、 preferred を渡せばハッシュアルゴリズムを変更できます。各ハッシャーのアルゴリズム名については Django に含まれるハッシャー を参照してください。

Changed in Django 5.0:

acheck_password() メソッドが追加されました。

make_password(password, salt=None, hasher='default')

このアプリケーションで使用する形式でハッシュ化されたパスワードを作成します。必須引数は1つで、プレーンテキスト(文字列またはバイト)のパスワードです。オプションとして、デフォルトを使用したくない場合に使用するソルトとハッシュアルゴリズムを指定できます (PASSWORD_HASHERS 設定の最初のエントリ)。各ハッシャーのアルゴリズム名については Django に含まれるハッシャー を参照してください。password 引数に None を指定すると、使用できないパスワードが返されます (check_password() では決して受け付けられません)。

is_password_usable(encoded_password)

パスワードが User.set_unusable_password() の結果の場合は False を返します。

パスワードの妥当性検証

ユーザーは、良くないパスワードを選択することがあります。この問題を軽減するために、Djangoはプラガブルなパスワードの妥当性検証を提供しています。複数のパスワードの妥当性検証を同時に設定できます。いくつかのバリデータは Django に含まれていますが、自分で書くこともできます。

各パスワードのバリデータは、ユーザーに要件の説明文を与え、指定されたパスワードの妥当性検証を行い、要件を満たしていない場合はエラーメッセージを返し、オプションでユーザのパスワードが変更されたときに通知するコールバックを定義します。バリデータは、動作を細かく指定するためのオプション設定を持つこともできます。

妥当性検証は AUTH_PASSWORD_VALIDATORS の設定で管理されます。設定のデフォルトは、空のリストになってます。これは、ひとつもバリデータが適用されていないことを意味しています。 startproject を使用して作られた新しいプロジェクトでは、バリデータのセットはデフォルトで有効になっています。

デフォルトでは、バリデータはパスワードをリセットまたは変更するフォームと createsuperuserchangepassword 管理コマンドで使用されます。たとえば、 User.objects.create_user()create_superuser() のようなモデルレベルではバリデータは適用されません。なぜなら、このレベルで Django とやりとりするのはユーザ ではなく開発者であると想定しているからであり、また、モデルのバリデーションがモデル作成の一環として自動的に実行されるわけではないからです。

注釈

パスワードの妥当性検証は多くの脆弱なパスワードの形式が使用されることを防ぎます。しかしながら、パスワードが全てのバリデータを通過するという事実は、強力なパスワードであることを保証するわけではありません。最も先進的なパスワードのバリデータでさえ検出できない、パスワードを弱めうる多くの要素があります。

パスワードの妥当性検証を有効にする

パスワードの妥当性検証は AUTH_PASSWORD_VALIDATORS で構成されます:

AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
        "OPTIONS": {
            "min_length": 9,
        },
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]

本例では組み込みの4つ全てのバリデータを有効化します。

  • UserAttributeSimilarityValidator は、パスワードとユーザの属性との類似性をチェックします。
  • MinimumLengthValidator は、パスワードが最小の長さを満たしているかをチェックします。このバリデータはカスタムオプションで構成されます。現在の設定では、最小長さは、デフォルトの8文字ではなく、9文字になっています。
  • CommonPasswordValidator は、一般的なパスワードのリストにそのパスワードが入っていないかをチェックします。デフォルトでは、組み込まれた20,000個のパスワードのリストと比較します。
  • NumericPasswordValidator は、パスワードが全体的に数値ではないかをチェックします。

UserAttributeSimilarityValidatorCommonPasswordValidator については、たとえばこの例ではデフォルトの設定を使用しています。 NumericPasswordValidator には設定はありません。

パスワードバリデーションのヘルプテキストとエラーは、常に AUTH_PASSWORD_VALIDATORS に記載されているソート順に返されます。

Django に含まれるバリデータ

Django には 4 つのバリデータがあります:

class MinimumLengthValidator(min_length=8)

パスワードが最小限の長さであることを検証します。最小の長さは min_length パラメータでカスタマイズできます。

class UserAttributeSimilarityValidator(user_attributes=DEFAULT_USER_ATTRIBUTES, max_similarity=0.7)

パスワードがユーザの特定の属性と十分に異なることを検証します。

パラメータ user_attributes は、比較するユーザー属性の名前のイテラブルでなければなりません。この引数が指定されない場合、デフォルトが使用されます。'username', 'first_name', 'last_name', 'email' です。存在しない属性は無視されます。

パスワードの最大類似度は max_similarity パラメータで 0.1 から 1.0 の範囲で指定できます。これは difflib.SequenceMatcher.quick_ratio() の結果と比較されます。0.1の値を指定すると、 user_attributes と大幅に異なるパスワード以外は拒否され、1.0の値を指定すると、属性の値と同じパスワードのみが拒否されます。

Changed in Django 2.2.26:

パラメータ max_similarity は最小値0.1に制限されました。

class CommonPasswordValidator(password_list_path=DEFAULT_PASSWORD_LIST_PATH)

パスワードが一般的なパスワードでないことを検証します。これはパスワードを小文字に変換し(大文字小文字を区別しない比較を行うため)、 Royce Williams によって作成された20,000の一般的なパスワードのリストと照合します。

password_list_path には一般的なパスワードのカスタムファイルのパスを指定できます。このファイルには1行につき1つの小文字のパスワードが含まれている必要があり、プレーンテキストまたはgzip圧縮されている必要があります。

Changed in Django 4.2:

一般的なパスワード2万件のリストを最新版に更新しました。

class NumericPasswordValidator

パスワードが数字のみでないことを確認します。

バリデーションの統合

django.contrib.auth.password_validation には、独自のフォームや他のコードから呼び出して パスワード認証を統合できる関数がいくつかあります。これは、たとえばパスワードの設定にカスタムフォームを使ったり、 パスワードの設定を許可する API 呼び出しがある場合に便利です。

validate_password(password, user=None, password_validators=None)

パスワードを検証します。すべてのバリデータがパスワードを有効と判定した場合、 None を返します。1つ以上のバリデータがパスワードを拒否した場合、バリデータからのすべてのエラーメッセージと共に ValidationError を発生させます。

もし user オブジェクトを指定しなかった場合、バリデータによってはバリデーションを実行できず、任意のパスワードを受け取ってしまう可能性があります。

password_changed(password, user=None, password_validators=None)

パスワードが変更されたことをすべてのバリデータに通知します。これは、パスワードの再利用を防止するバリデータなどで使用します。パスワードの変更に成功したら、これを呼び出さなければなりません。

AbstractBaseUser のサブクラスでは、パスワードフィールドは set_password() を呼び出すと "dirty" としてマークされ、ユーザが保存された後に password_changed() が呼び出されます。

password_validators_help_texts(password_validators=None)

すべてのバリデータのヘルプテキストの一覧を返します。これらは、パスワードの条件をユーザに説明するものです。

password_validators_help_text_html(password_validators=None)

すべてのヘルプテキストを <ul> で囲んだ HTML 文字列を返します。これはフォームにパスワードバリデーションを追加する際に便利です。フォームフィールドの help_text パラメータに直接出力を渡すことができるからです。

get_password_validators(validator_config)

パラメータ validator_config に基づいてバリデータオブジェクトのセットを返します。デフォルトでは、すべての関数は AUTH_PASSWORD_VALIDATORS で定義されたバリデータを使用しますが、この関数を別のバリデータセットで呼び出して、その結果を他の関数の password_validators パラメータに渡すことで、カスタムバリデータセットを代わりに使用できます。これは、たいていの場面で使用する典型的なバリデータセットがありながら、 特別な場面で独自のバリデータセットが必要になる場合に便利です。常に同じバリデータを使う場合は、この関数を使う必要はありません。 AUTH_PASSWORD_VALIDATORS の設定がデフォルトで使われるからです。

validator_config の構造は AUTH_PASSWORD_VALIDATORS の構造と同じです。この関数の戻り値は上記の関数の password_validators パラメータに渡すことができます。

これらの関数にパスワードが渡される場合は、ハッシュ化されたパスワードではなく、常に平文のパスワードでなければならないことに注意してください。

独自のバリデータを書く

Django の組み込みバリデータでは不十分な場合、自分でパスワードバリデータ を書くことができます。バリデータはとても小さなインタフェースを持っています。2 つのメソッドを実装しなければなりません:

  • validate(self, password, user=None): パスワードを検証します。パスワードが有効な場合は None を返し、パスワードが無効な場合はエラーメッセージと共に ValidationError を発生させます。もし userNone であった場合、バリデータが実行できないので、 None を返してエラーにならないようにしてください。
  • get_help_text(): ユーザに要件を説明するためのヘルプテキストを提供します。

バリデータの AUTH_PASSWORD_VALIDATORSOPTIONS にあるすべての項目がコンストラクタに渡されます。コンストラクタの引数にはデフォルト値を指定します。

以下は、1つのオプション設定を持つ基本的なバリデータの例です。

from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _


class MinimumLengthValidator:
    def __init__(self, min_length=8):
        self.min_length = min_length

    def validate(self, password, user=None):
        if len(password) < self.min_length:
            raise ValidationError(
                _("This password must contain at least %(min_length)d characters."),
                code="password_too_short",
                params={"min_length": self.min_length},
            )

    def get_help_text(self):
        return _(
            "Your password must contain at least %(min_length)d characters."
            % {"min_length": self.min_length}
        )

パスワードの変更が成功した後に呼び出される password_changed(password, user=None) を実装することもできます。これはたとえばパスワードの再利用を防ぐために使用できます。しかし、ユーザーの以前のパスワードを保存することにした場合、決して平文で保存してはいけません。

Back to Top