Password Hashing and Verification

Most applications use passwords to login users. These passwords should be hashed to securely store them. Symfony's PasswordHasher component provides all utilities to safely hash and verify passwords.

ほとんどのアプリケーションは、パスワードを使用してユーザーをログインさせます。これらのパスワードは、ハッシュして安全に保管する必要があります。 Symfony の PasswordHasher コンポーネントは、パスワードを安全にハッシュして検証するためのすべてのユーティリティを提供します。

Make sure it is installed by running:

次を実行して、インストールされていることを確認します。
1
$ composer require symfony/password-hasher

Configuring a Password Hasher

Before hashing passwords, you must configure a hasher using the password_hashers option. You must configure the hashing algorithm and optionally some algorithm options:

パスワードをハッシュする前に、password_hashers オプションを使用してハッシャーを構成する必要があります。ハッシュ アルゴリズムと、必要に応じていくつかのアルゴリズム オプションを構成する必要があります。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
  • Standalone Use
    スタンドアロン使用
1
2
3
4
5
6
7
8
9
10
11
12
# config/packages/security.yaml
security:
    # ...

    password_hashers:
        # auto hasher with default options for the User class (and children)
        App\Entity\User: 'auto'

        # auto hasher with custom options for all PasswordAuthenticatedUserInterface instances
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
            algorithm: 'auto'
            cost:      15

In this example, the "auto" algorithm is used. This hasher automatically selects the most secure algorithm available on your system. Combined with password migration, this allows you to always secure passwords in the safest way possible (even when new algorithms are introduced in future PHP releases).

この例では、「自動」アルゴリズムが使用されています。このハッシャーは、システムで利用可能な最も安全なアルゴリズムを自動的に選択します。これをパスワードの移行と組み合わせることで、可能な限り最も安全な方法で常にパスワードを保護することができます (将来の PHP リリースで新しいアルゴリズムが導入された場合でも)。

Further in this article, you can find a full reference of all supported algorithms.

さらにこの記事では、サポートされているすべてのアルゴリズムの完全なリファレンスを見つけることができます。

Tip

ヒント

Hashing passwords is resource intensive and takes time in order to generate secure password hashes. In general, this makes your password hashing more secure.

パスワードのハッシュはリソースを集中的に使用し、安全なパスワード ハッシュを生成するには時間がかかります。一般に、これによりパスワードハッシュがより安全になります。

In tests however, secure hashes are not important, so you can change the password hasher configuration in test environment to run tests faster:

ただし、テストでは安全なハッシュは重要ではないため、テスト環境でパスワード ハッシャーの構成を変更して、テストをより高速に実行できます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# config/packages/test/security.yaml
security:
    # ...

    password_hashers:
        # Use your user class name here
        App\Entity\User:
            algorithm: plaintext # disable hashing (only do this in tests!)

        # or use the lowest possible values
        App\Entity\User:
            algorithm: auto # This should be the same value as in config/packages/security.yaml
            cost: 4 # Lowest possible value for bcrypt
            time_cost: 3 # Lowest possible value for argon
            memory_cost: 10 # Lowest possible value for argon

Hashing the Password

After configuring the correct algorithm, you can use the UserPasswordHasherInterface to hash and verify the passwords:

正しいアルゴリズムを設定したら、UserPasswordHasherInterface を使用してパスワードをハッシュおよび検証できます。
  • Framework Use
    フレームワークの使用
  • Standalone Use
    スタンドアロン使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// src/Controller/RegistrationController.php
namespace App\Controller;

// ...
use
Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class UserController extends AbstractController
{
    public function registration(UserPasswordHasherInterface $passwordHasher)
    {
        // ... e.g. get the user data from a registration form
        $user = new User(...);
        $plaintextPassword = ...;

        // hash the password (based on the security.yaml config for the $user class)
        $hashedPassword = $passwordHasher->hashPassword(
            $user,
            $plaintextPassword
        );
        $user->setPassword($hashedPassword);

        // ...
    }

    public function delete(UserPasswordHasherInterface $passwordHasher, UserInterface $user)
    {
        // ... e.g. get the password from a "confirm deletion" dialog
        $plaintextPassword = ...;

        if (!$passwordHasher->isPasswordValid($user, $plaintextPassword)) {
            throw new AccessDeniedHttpException();
        }
    }
}

Reset Password

Using MakerBundle and SymfonyCastsResetPasswordBundle, you can create a secure out of the box solution to handle forgotten passwords. First, install the SymfonyCastsResetPasswordBundle:

MakerBundle と SymfonyCastsResetPasswordBundle を使用すると、忘れたパスワードを処理するための、すぐに使える安全なソリューションを作成できます。まず、SymfonyCastsResetPasswordBundle をインストールします。
1
$ composer require symfonycasts/reset-password-bundle

Then, use the make:reset-password command. This asks you a few questions about your app and generates all the files you need! After, you'll see a success message and a list of any other steps you need to do.

次に、make:reset-password コマンドを使用します。これにより、アプリに関するいくつかの質問が表示され、必要なすべてのファイルが生成されます。その後、成功メッセージと、実行する必要があるその他の手順のリストが表示されます。
1
$ php bin/console make:reset-password

You can customize the reset password bundle's behavior by updating the reset_password.yaml file. For more information on the configuration, check out the SymfonyCastsResetPasswordBundle guide.

reset_password.yaml ファイルを更新することで、パスワードのリセット バンドルの動作をカスタマイズできます。設定の詳細については、SymfonyCastsResetPasswordBundleguide を確認してください。

Password Migration

In order to protect passwords, it is recommended to store them using the latest hash algorithms. This means that if a better hash algorithm is supported on your system, the user's password should be rehashed using the newer algorithm and stored. That's possible with the migrate_from option:

パスワードを保護するために、latesthash アルゴリズムを使用してパスワードを保存することをお勧めします。これは、より優れたハッシュ アルゴリズムがシステムでサポートされている場合、新しいアルゴリズムを使用してユーザーのパスワードを再ハッシュし、保存する必要があることを意味します。これは、migrate_from オプションで可能です。
  1. Configure a new Hasher Using "migrate_from"
    「migrate_from」を使用して新しい Hasher を構成する
  2. Upgrade the Password
    パスワードのアップグレード
  3. Optionally, Trigger Password Migration From a Custom Hasher
    オプションで、カスタム ハッシャーからパスワード移行をトリガーする

Configure a new Hasher Using "migrate_from"

When a better hashing algorithm becomes available, you should keep the existing hasher(s), rename it, and then define the new one. Set the migrate_from option on the new hasher to point to the old, legacy hasher(s):

より優れたハッシュ アルゴリズムが利用可能になったら、既存のハッシャーを保持し、名前を変更してから、新しいハッシュ アルゴリズムを定義する必要があります。古いレガシー ハッシャーを指すように、新しいハッシャーの migrate_from オプションを設定します。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
  • Standalone Use
    スタンドアロン使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# config/packages/security.yaml
security:
    # ...

    password_hashers:
        # a hasher used in the past for some users
        legacy:
            algorithm: sha256
            encode_as_base64: false
            iterations: 1

        App\Entity\User:
            # the new hasher, along with its options
            algorithm: sodium
            migrate_from:
                - bcrypt # uses the "bcrypt" hasher with the default options
                - legacy # uses the "legacy" hasher configured above

With this setup:

このセットアップでは:
  • New users will be hashed with the new algorithm;
    新しいユーザーは新しいアルゴリズムでハッシュされます。
  • Whenever a user logs in whose password is still stored using the old algorithm, Symfony will verify the password with the old algorithm and then rehash and update the password using the new algorithm.
    パスワードがまだ古いアルゴリズムを使用して保存されているユーザーがログインするたびに、Symfony は古いアルゴリズムでパスワードを検証し、新しいアルゴリズムを使用してパスワードを更新し直します。

Tip

ヒント

The auto, native, bcrypt and argon hashers automatically enable password migration using the following list of migrate_from algorithms:

自動、ネイティブ、bcrypt、およびアルゴン ハッシャーは、次のリストの migrate_from アルゴリズムを使用して、パスワードの移行を自動的に有効にします。
  1. PBKDF2 (which uses hash_pbkdf2);
    PBKDF2 (hash_pbkdf2 を使用);
  2. Message digest (which uses hash)
    メッセージ ダイジェスト (ハッシュを使用)

Both use the hash_algorithm setting as the algorithm. It is recommended to use migrate_from instead of hash_algorithm, unless the auto hasher is used.

どちらもアルゴリズムとして hash_algorithm 設定を使用します。 autohasher を使用しない限り、hash_algorithm の代わりに migrate_from を使用することをお勧めします。

Upgrade the Password

Upon successful login, the Security system checks whether a better algorithm is available to hash the user's password. If it is, it'll hash the correct password using the new hash. When using a custom authenticator, you must use the PasswordCredentials in the security passport.

ログインに成功すると、セキュリティ システムは、ユーザーのパスワードをハッシュするためのより優れたアルゴリズムが利用可能かどうかをチェックします。そうであれば、新しいハッシュを使用して正しいパスワードをハッシュします。カスタム オーセンティケータを使用する場合は、セキュリティ パスポートで PasswordCredentials を使用する必要があります。

You can enable the upgrade behavior by implementing how this newly hashed password should be stored:

この新しくハッシュされたパスワードを保存する方法を実装することで、アップグレードの動作を有効にすることができます。

After this, you're done and passwords are always hashed as securely as possible!

この後、作業は完了し、パスワードは常に可能な限り安全にハッシュされます!

Note

ノート

When using the PasswordHasher component outside a Symfony application, you must manually use the PasswordHasherInterface::needsRehash() method to check if a rehash is needed and PasswordHasherInterface::hash() method to rehash the plaintext password using the new algorithm.

Symfony アプリケーションの外部で PasswordHasher コンポーネントを使用する場合、手動で PasswordHasherInterface::needsRehash() メソッドを使用して再ハッシュが必要かどうかを確認し、PasswordHasherInterface::hash() メソッドを使用して新しいアルゴリズムを使用して平文のパスワードを再ハッシュする必要があります。

Upgrade the Password when using Doctrine

When using the entity user provider, implement PasswordUpgraderInterface in the UserRepository (see the Doctrine docs for information on how to create this class if it's not already created). This interface implements storing the newly created password hash:

エンティティ ユーザー プロバイダーを使用する場合は、UserRepository に PasswordUpgraderInterface を実装します (このクラスがまだ作成されていない場合の作成方法については、Doctrine のドキュメントを参照してください)。このインターフェースは、新しく作成されたパスワード ハッシュの保存を実装します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// src/Repository/UserRepository.php
namespace App\Repository;

// ...
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;

class UserRepository extends EntityRepository implements PasswordUpgraderInterface
{
    // ...

    public function upgradePassword(UserInterface $user, string $newHashedPassword): void
    {
        // set the new hashed password on the User object
        $user->setPassword($newHashedPassword);

        // execute the queries on the database
        $this->getEntityManager()->flush();
    }
}

Upgrade the Password when using a Custom User Provider

If you're using a custom user provider, implement the PasswordUpgraderInterface in the user provider:

カスタム ユーザー プロバイダーを使用している場合は、ユーザー プロバイダーに PasswordUpgraderInterface を実装します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Security/UserProvider.php
namespace App\Security;

// ...
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;

class UserProvider implements UserProviderInterface, PasswordUpgraderInterface
{
    // ...

    public function upgradePassword(UserInterface $user, string $newHashedPassword): void
    {
        // set the new hashed password on the User object
        $user->setPassword($newHashedPassword);

        // ... store the new password
    }
}

Trigger Password Migration From a Custom Hasher

If you're using a custom password hasher, you can trigger the password migration by returning true in the needsRehash() method:

カスタム パスワード ハッシャーを使用している場合は、needsRehash() メソッドで true を返すことで passwordmigration をトリガーできます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Security/CustomPasswordHasher.php
namespace App\Security;

// ...
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;

class CustomPasswordHasher implements UserPasswordHasherInterface
{
    // ...

    public function needsRehash(string $hashed): bool
    {
        // check whether the current password is hashed using an outdated hasher
        $hashIsOutdated = ...;

        return $hashIsOutdated;
    }
}

Dynamic Password Hashers

Usually, the same password hasher is used for all users by configuring it to apply to all instances of a specific class. Another option is to use a "named" hasher and then select which hasher you want to use dynamically.

通常、特定のクラスのすべてのインスタンスに適用されるように構成することで、すべてのユーザーに同じパスワード ハッシャーが使用されます。別のオプションは、「名前付き」ハッシャーを使用してから、使用するハッシャーを動的に選択することです。

By default (as shown at the start of the article), the auto algorithm is used for App\Entity\User.

デフォルトでは (記事の冒頭で示したように)、auto アルゴリズムが App\Entity\User に使用されます。

This may be secure enough for a regular user, but what if you want your admins to have a stronger algorithm, for example auto with a higher cost. This can be done with named hashers:

これは通常のユーザーにとっては十分に安全かもしれませんが、より強力なアルゴリズムを管理者に持たせたい場合はどうすればよいでしょうか。これは、名前付きハッシャーを使用して実行できます。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
  • Standalone Use
    スタンドアロン使用
1
2
3
4
5
6
7
# config/packages/security.yaml
security:
    # ...
    password_hashers:
        harsh:
            algorithm: auto
            cost: 15

This creates a hasher named harsh. In order for a User instance to use it, the class must implement PasswordHasherAwareInterface. The interface requires one method - getPasswordHasherName() - which should return the name of the hasher to use:

これにより、arsh という名前のハッシュが作成されます。 User インスタンスがそれを使用するためには、クラスは PasswordHasherAwareInterface を実装する必要があります。インターフェースには getPasswordHasherName() という 1 つのメソッドが必要です。このメソッドは使用するハッシュの名前を返す必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/Entity/User.php
namespace App\Entity;

use Symfony\Component\PasswordHasher\Hasher\PasswordHasherAwareInterface;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class User implements
    UserInterface,
    PasswordAuthenticatedUserInterface,
    PasswordHasherAwareInterface
{
    // ...

    public function getPasswordHasherName(): ?string
    {
        if ($this->isAdmin()) {
            return 'harsh';
        }

        return null; // use the default hasher
    }
}

Caution

注意

When migrating passwords, you don't need to implement PasswordHasherAwareInterface to return the legacy hasher name: Symfony will detect it from your migrate_from configuration.

パスワードを移行するとき、PasswordHasherAwareInterface を実装して legacyhasher 名を返す必要はありません: Symfony は、migrate_from 構成からそれを検出します。

If you created your own password hasher implementing the PasswordHasherInterface, you must register a service for it in order to use it as a named hasher:

PasswordHasherInterface を実装する独自のパスワード ハッシャーを作成した場合は、名前付きハッシャーとして使用するためにサービスを登録する必要があります。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
# config/packages/security.yaml
security:
    # ...
    password_hashers:
        app_hasher:
            id: 'App\Security\Hasher\MyCustomPasswordHasher'

This creates a hasher named app_hasher from a service with the ID App\Security\Hasher\MyCustomPasswordHasher.

これにより、IDApp\Security\Hasher\MyCustomPasswordHasher を持つサービスから app_hasher という名前のハッシャーが作成されます。

Supported Algorithms

The "auto" Hasher

It automatically selects the best available hasher (currently Bcrypt). If PHP or Symfony adds new password hashers in the future, it might select a different hasher.

利用可能な最適なハッシュ (現在は Bcrypt) を自動的に選択します。将来、PHP または Symfony が新しいパスワード ハッシャーを追加する場合、別のハッシャーが選択される可能性があります。

Because of this, the length of the hashed passwords may change in the future, so make sure to allocate enough space for them to be persisted (varchar(255) should be a good setting).

このため、ハッシュ化されたパスワードの長さは将来変更される可能性があるため、パスワードを永続化するために十分なスペースを確保してください (varchar(255) が適切な設定です)。

The Bcrypt Password Hasher

It produces hashed passwords with the bcrypt password hashing function. Hashed passwords are 60 characters long, so make sure to allocate enough space for them to be persisted. Also, passwords include the cryptographic salt inside them (it's generated automatically for each new password) so you don't have to deal with it.

これは、bcrypt パスワード ハッシュ関数を使用してハッシュ化されたパスワードを生成します。ハッシュ化されたパスワードは 60 文字の長さであるため、永続化するために十分なスペースを割り当てるようにしてください。また、パスワードには暗号ソルトが含まれているため (新しいパスワードごとに自動的に生成されます)、それを処理する必要はありません。

Its only configuration option is cost, which is an integer in the range of 4-31 (by default, 13). Each single increment of the cost doubles the time it takes to hash a password. It's designed this way so the password strength can be adapted to the future improvements in computation power.

その唯一の構成オプションは cost です。これは、4 から 31 の範囲の整数 (デフォルトでは 13) です。コストが 1 つ増えるごとに、パスワードのハッシュにかかる時間が 2 倍になります。このように設計されているため、将来の計算能力の向上に合わせてパスワードの強度を調整できます。

You can change the cost at any time — even if you already have some passwords hashed using a different cost. New passwords will be hashed using the new cost, while the already hashed ones will be validated using a cost that was used back when they were hashed.

コストはいつでも変更できます — 別のコストを使用してパスワードを既にハッシュ化していても.新しいパスワードは newcost を使用してハッシュされますが、既にハッシュされたパスワードは、ハッシュされたときに使用されたコストを使用して検証されます。

Tip

ヒント

A simple technique to make tests much faster when using BCrypt is to set the cost to 4, which is the minimum value allowed, in the test environment configuration.

BCrypt を使用するときにテストを大幅に高速化する簡単な方法は、テスト環境の構成で、コストを 4 に設定することです。これは、許容される最小値です。

The Sodium Password Hasher

It uses the Argon2 key derivation function. Argon2 support was introduced in PHP 7.2 by bundling the libsodium extension.

Argon2 鍵導出関数を使用します。 Argon2 のサポートは、PHP 7.2 で libsodium 拡張機能をバンドルすることによって導入されました。

The hashed passwords are 96 characters long, but due to the hashing requirements saved in the resulting hash this may change in the future, so make sure to allocate enough space for them to be persisted. Also, passwords include the cryptographic salt inside them (it's generated automatically for each new password) so you don't have to deal with it.

ハッシュ化されたパスワードの長さは 96 文字ですが、結果のハッシュに保存されるハッシュ要件により、これは将来変更される可能性があるため、永続化するために十分なスペースを割り当てるようにしてください。また、パスワードには暗号ソルトが含まれているため (新しいパスワードごとに自動的に生成されます)、それを処理する必要はありません。

The PBKDF2 Hasher

Using the PBKDF2 hasher is no longer recommended since PHP added support for Sodium and BCrypt. Legacy application still using it are encouraged to upgrade to those newer hashing algorithms.

PHP が Sodium と BCrypt のサポートを追加したため、PBKDF2 ハッシャーの使用は推奨されなくなりました。まだそれを使用しているレガシー アプリケーションは、これらの新しいハッシュ アルゴリズムにアップグレードすることをお勧めします。

Creating a custom Password Hasher

If you need to create your own, it needs to follow these rules:

独自に作成する必要がある場合は、次の規則に従う必要があります。
  1. The class must implement PasswordHasherInterface (you can also implement LegacyPasswordHasherInterface if your hash algorithm uses a separate salt);
    クラスは PasswordHasherInterface を実装する必要があります (ハッシュ アルゴリズムが別のソルトを使用する場合は、LegacyPasswordHasherInterface も実装できます)。
  2. The implementations of hash() and verify() must validate that the password length is no longer than 4096 characters. This is for security reasons (see CVE-2013-5750).

    hash() および verify() の実装では、パスワードの長さが 4096 文字を超えていないことを検証する必要があります。これはセキュリティ上の理由によるものです (CVE-2013-5750 を参照)。

    You can use the isPasswordTooLong() method for this check.

    このチェックには isPasswordTooLong() メソッドを使用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// src/Security/Hasher/CustomVerySecureHasher.php
namespace App\Security\Hasher;

use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
use Symfony\Component\PasswordHasher\Hasher\CheckPasswordLengthTrait;
use Symfony\Component\PasswordHasher\PasswordHasherInterface;

class CustomVerySecureHasher implements PasswordHasherInterface
{
    use CheckPasswordLengthTrait;

    public function hash(string $plainPassword): string
    {
        if ($this->isPasswordTooLong($plainPassword)) {
            throw new InvalidPasswordException();
        }

        // ... hash the plain password in a secure way

        return $hashedPassword;
    }

    public function verify(string $hashedPassword, string $plainPassword): bool
    {
        if ('' === $plainPassword || $this->isPasswordTooLong($plainPassword)) {
            return false;
        }

        // ... validate if the password equals the user's password in a secure way

        return $passwordIsValid;
    }
}

Now, define a password hasher using the id setting:

次に、id 設定を使用してパスワード ハッシャーを定義します。
  • YAML
    YAML
  • XML
    XML
  • PHP
    PHP
1
2
3
4
5
6
7
# config/packages/security.yaml
security:
    # ...
    password_hashers:
        app_hasher:
            # the service ID of your custom hasher (the FQCN using the default services.yaml)
            id: 'App\Security\Hasher\MyCustomPasswordHasher'