Note: This article has been updated with additional technical information about the structure of password hashes that may be relevant to developers of plugins that directly handle them.
The underlying algorithm that’s used to hash and store user passwords in the database will be changed in WordPress 6.8 from phpass portable hashing to bcrypt. The adoption of bcrypt hardens password security in WordPress by significantly increasing the computational cost of cracking a password hash.
In addition, application passwords, user password reset keys, personal data request keys, and the recovery mode key will switch from using phpass to the cryptographically secure but fast BLAKE2b hashing algorithm via Sodium.
No action needs to be taken by site owners or users as a result of these changes. Passwords and security keys that were saved in prior versions of WordPress will continue to work after updating to 6.8. Users don’t need to change or reset their passwords, logged in users will remain logged in, and their sessions will remain valid.
When a user first subsequently logs in after the update – or when they next change their password – their password will automatically get rehashed with bcrypt and resaved in the database. Application passwords and security keys will not get automatically rehashed, but an existing hash will remain valid if it was generated prior to WordPress 6.8 and used before it expires.
Note that post passwords will continue to use phpass portable hashing for now. This may change in the future after further investigation has been done on how best to improve the hashing and checking mechanism of post passwords.
Portability
Hashes that are generated by the phpass portable hashing algorithm are portable between different sites, environments, and servers. This portability doesn’t change with this switch to bcrypt and BLAKE2b, so you can move your database from one server to another and update to newer versions of PHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher and WordPress and the password hashes will continue to function as expected.
Updates to password handling functions
The wp_hash_password()
and wp_check_password()
functions have been updated to use the PHP native password_hash()
and password_verify()
functions with the bcrypt algorithm and SHA-384 pre-hashing. Both functions retain support for the $wp_hasher
global object in case that’s being used to implement an alternative hashing mechanism.
The wp_check_password()
function retains support for passwords that were hashed using phpass, which means existing password hashes won’t be invalidated.
A new wp_password_needs_rehash()
function has been introduced as a wrapper for password_needs_rehash()
. If a plugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party needs to adjust its logic then the password_needs_rehash
filter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. can be used. The function is also pluggable, so it can be overridden if absolutely necessary.
Pre-hashing with SHA-384 is implemented in order to avoid the 72 byte length limit imposed on passwords by bcrypt. Password hashes are therefore stored with a $wp
prefix to distinguish them from vanilla bcrypt hashes which may be in use via a plugin. By default this means the full prefix will be $wp$2y$
.
New fast hashing functions
The following functions have been introduced as wrappers for the cryptographically secure but fast BLAKE2b algorithm via Sodium:
wp_fast_hash()
Used to hash a string that is randomly generated using sufficiently high entropy, preferably over 128 bits for values that don’t have a corresponding expiry mechanism.
wp_verify_fast_hash()
Used to verify a hash generated via wp_fast_hash()
, with fallback support for phpass portable hashes.
Do developers need to do anything?
Code that calls wp_hash_password()
and wp_check_password()
will continue to work as expected and does not need to change.
Code that directly handles phpass hashes may need to be updated, for example:
- Code that assumes the existence of the
$P$
prefix on hashes. The code will need to be updated so it either doesn’t need to inspect the prefix of the hash at all, or updated to handle both the new prefixes and hashing algorithms and legacy hashes:
- The
$wp$2y$
prefix will be the new default for user passwords in WordPress and represents a SHA-384 pre-hashed bcrypt hash.
- The plain
$2y$
prefix may be used by existing plugins that use bcrypt hashes without pre-hashing.
- The
$generic$
prefix for a BLAKE2b hash used for application passwords and security keys.
- A hash starting with
$argon2
if a site opts in to using an Argon2 algorithm (see below). Note that any non-bcrypt algorithm won’t use pre-hashing and therefore won’t include $wp
at the start of the prefix.
- The old
$P$
prefix for a phpass portable hash which will remain in wide use.
- A legacy plain MD5 hash, which is a 32 character hexadecimal string.
- Code that otherwise directly interacts with the hashed value of a user password. If such hashes are validated directly, this should be done via
wp_check_password()
.
- Code that otherwise directly interacts with the hashed value of an application password, password reset key, personal data request key, or the recovery mode key. If such hashes are validated directly, this should be done via the new
wp_verify_fast_hash()
function.
- Any plugin that overwrites the pluggable
wp_hash_password()
and wp_check_password()
functions. Unless these functions specifically implement another hashing algorithm, they can be removed in order to allow the bcrypt implementation in 6.8 to take effect.
Alternative authentication mechanisms such as single sign-on (SSO), social login, or one-time login are unlikely to be affected by this change, however you should still verify whether your specific implementation includes any handling of password hashes or security keys. Multi-factor (MFA and 2FA) implementations are also unlikely to be affected by this change.
What about Argon2?
Servers that support Argon2 can enable its usage with this single line of code in WordPress 6.8 and later:
add_filter( 'wp_hash_password_algorithm', fn() => PASSWORD_ARGON2ID );
If necessary, the password_algos()
function should be used to first check for argon2id
support. Unfortunately it’s not possible to rely on Argon2 being available on all servers because it requires both libargon2
to be available on the server and for PHP to be built with Argon2 support enabled. The sodium_compat
library does not provide an implementation of Argon2.
Acknowledgements
We can’t pretend that switching to bcrypt for user-generated passwords is a recent proposal. Ideally the switch would have been made back when the increase to the minimum supported version of PHP facilitated this change. However, this change has now been made and it helps future-proof further improvements to password hashing, including increases to the bcrypt cost in newer versions of PHP.
Many thanks go to the Roots team for maintaining their bcrypt password hashing package for WordPress as well as the many contributors on the Trac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. tickets and GitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged be the repository owner. https://github.com/ pull requests.
Further technical information
Further technical information, technical FAQs, and implementation details can be seen on the GitHub pull request for this change and in the discussion on the Trac ticket.
In case you need to know:
- User passwords are stored as a hash in the
wp_users.user_pass
field in the database.
- Application passwords are stored as a hash in a JSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. serialized object in the
wp_usermeta
table using the _application_passwords
key.
- User password reset keys are stored as a hash in the
wp_users.user_activation_key
field in the database.
- Personal data request keys are stored as a hash in the
wp_posts.post_password
field in the database against the post that represents the personal data request.
- The recovery mode key is stored as a hash in the
recovery_keys
option in the wp_options
database table.
Thanks to @desrosj and @joehoyle for helping review this post.
#6-8, #dev-notes