8000 Added article on password migrations · symfony/symfony-docs@2f4e7c4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2f4e7c4

Browse files
committed
Added article on password migrations
1 parent d5ec360 commit 2f4e7c4

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed

security.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,7 @@ Authentication (Identifying/Logging in the User)
987987

988988
security/form_login_setup
989989
security/guard_authentication
990+
security/migrating_password_hashes
990991
security/auth_providers
991992
security/user_provider
992993
security/ldap
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
.. index::
2+
single: Security; How to Migrate a Password Hash
3+
4+
How to Migrate a Password Hash
5+
==============================
6+
7+
.. versionadded:: 4.4
8+
9+
Password migration was introduced in Symfony 4.4.
10+
11+
In order to protect passwords, it is recommended to store them using the latest
12+
hash algorithms. This means that if a better hash algorithm is supported on the
13+
system, the user's password should be rehashed and stored. Symfony provides this
14+
functionality when a user is succesfully authenticated.
15+
16+
To enable this, make sure you apply the following steps to your application:
17+
18+
#. `Configure the "auto" Encoder`_
19+
#. `Upgrade the Password`_
20+
#. Optionally, `Trigger Password Migration From a Custom Encoder`_
21+
22+
Configure the "auto" Encoder
23+
----------------------------
24+
25+
The "auto" encoder is able to verify the hash of a number of different
26+
algorithms and can also hash new plain text passwords.
27+
28+
.. configuration-block::
29+
30+
.. code-block:: yaml
31+
32+
# config/packages/security.yaml
33+
security:
34+
# ...
35+
36+
encoders:
37+
App\Entity\User:
38+
algorithm: auto
39+
cost: 14
40+
41+
.. code-block:: xml
42+
43+
<!-- config/packages/security.xml -->
44+
<?xml version="1.0" encoding="UTF-8"?>
45+
<srv:container xmlns="http://symfony.com/schema/dic/security"
46+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
47+
xmlns:srv="http://symfony.com/schema/dic/services"
48+
xsi:schemaLocation="http://symfony.com/schema/dic/services
49+
https://symfony.com/schema/dic/services/services-1.0.xsd">
50+
51+
<config>
52+
<!-- ... -->
53+
54+
<encoder class="App\Entity\User"
55+
algorithm="auto"
56+
cost="14"/>
57+
58+
<!-- ... -->
59+
</config>
60+
</srv:container>
61+
62+
.. code-block:: php
63+
64+
// config/packages/security.php
65+
$container->loadFromExtension('security', [
66+
// ...
67+
68+
'encoders' => [
69+
'App\Entity\User' => [
70+
'algorithm' => 'auto',
71+
'cost' => 14,
72+
]
73+
],
74+
75+
// ...
76+
]);
77+
78+
The auto encoder does this by using a list of encoders. The first algorithm in
79+
the list is used to hash new passwords. It is configured to use the following algorithms:
80+
81+
#. :ref:`Sodium <reference-security-sodium>` when available, otherwise native is used (which uses :phpfunction:`password_hash`);
82+
#. :ref:`PBKDF2 <reference-security-pbkdf2>` (which uses :phpfunction:`hash_pbkdf2`);
83+
#. The configured encoder in ``hash_algorithm``.
84+
85+
If you previously used the bcrypt encoder, they are supported through the
86+
Sodium and Native encoders. Any custom encoder previously used can be
87+
configured by setting ``hash_algorithm`` to the custom encoder name.
88+
89+
Upgrade the Password
90+
--------------------
91+
92+
Upon successful login, the Security system checks whether a better algorithm
93+
is available to hash the user's password. If it is, it'll hash the correct
94+
password using the new hash. You can enable this behavior by implementing how
95+
this newly hashed password should be stored:
96+
97+
* `When using Doctrine's entity user provider <Upgrade the Password when using Doctrine>`_
98+
* `When using a custom user provider <Upgrade the Password when using a custom User Provider>`_
99+
100+
After this, you're done and passwords are always hashed as secure as possible!
101+
102+
Upgrade the Password when using Doctrine
103+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104+
105+
When using the :ref:`entity user provider <security-entity-user-provider>`, implement
106+
:class:`Symfony\\Component\\Security\\Core\\User\\PasswordUpgraderInterface` in
107+
the ``UserRepository`` (see `the Doctrine docs for information`_ on how to
108+
create this class if it's not already created). This interface implements
109+
storing the newly created password hash::
110+
111+
// src/Repository/UserRepository.php
112+
namespace App\Repository;
113+
114+
// ...
115+
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
116+
117+
class UserRepository extends EntityRepository implements PasswordUpgraderInterface
118+
{
119+
// ...
120+
121+
public function upgradePassword(UserInterface $user, string $newEncodedPassword): void
122+
{
123+
// set the new encoded password on the User object
124+
$user->setPassword($newEncodedPassword);
125+
126+
// execute the queries on the database
127+
$this->getEntityManager->flush($user);
128+
}
129+
}
130+
131+
Upgrade the Password when using a custom User Provider
132+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
133+
134+
If you're using a :ref:`custom user provider <custom-user-provider>`, implement the
135+
:class:`Symfony\\Component\\Security\\Core\\User\\PasswordUpgraderInterface` in
136+
the user provider::
137+
138+
// src/Security/UserProvider.php
139+
namespace App\Security;
140+
141+
// ...
142+
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
143+
144+
class UserProvider implements UserProviderInterface, PasswordUpgraderInterface
145+
{
146+
// ...
147+
148+
public function upgradePassword(UserInterface $user, string $newEncodedPassword): void
149+
{
150+
// set the new encoded password on the User object
151+
$user->setPassword($newEncodedPassword);
152+
153+
// ... store the new password
154+
}
155+
}
156+
157+
Trigger Password Migration From a Custom Encoder
158+
------------------------------------------------
159+
160+
If you're using a custom password encoder, you can trigger the password
161+
migration by returning ``true`` in the ``needsRehash()`` method::
162+
163+
// src/Security/UserProvider.php
164+
namespace App\Security;
165+
166+
// ...
167+
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
168+
169+
class CustomPasswordEncoder implements PasswordEncoderInterface
170+
{
171+
// ...
172+
173+
public function needsRehash(string $encoded): bool
174+
{
175+
// check whether the current password is hash using an outdated encoder
176+
$hashIsOutdated = ...;
177+
178+
return $hashIsOutdated;
179+
}
180+
}
181+
182+
.. _`the Doctrine docs for information`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/working-with-objects.html#custom-repositories

0 commit comments

Comments
 (0)
0