Giter VIP home page Giter VIP logo

wp-password-bcrypt's Introduction

wp-password-bcrypt

MIT License Packagist Packagist Downloads Build Status Follow Roots

Drop-in bcrypt password hashing for WordPress
Built with ❤️

Supporting

wp-password-bcrypt is an open source project and completely free to use.

However, the amount of effort needed to maintain and develop new features and products within the Roots ecosystem is not sustainable without proper financial backing. If you have the capability, please consider donating using the links below:

Sponsor on GitHub Donate via Patreon Donate via PayPal

Overview

wp-password-bcrypt is a WordPress plugin to replace WP's outdated and insecure MD5-based password hashing with the modern and secure bcrypt.

This plugin requires PHP >= 5.5.0 which introduced the built-in password_hash and password_verify functions.

See Improving WordPress Password Security for more background on this plugin and the password hashing issue.

Requirements

Installation

This plugin is a Composer library so it can be installed in a few ways:

Composer Autoloaded

composer require roots/wp-password-bcrypt

wp-password-bcrypt.php file will be automatically autoloaded by Composer and it won't appear in your plugins.

Manually as a must-use plugin

If you don't use Composer, you can manually copy wp-password-bcrypt.php into your mu-plugins folder.

We do not recommend using this as a normal (non-mu) plugin. It makes it too easy to disable or remove the plugin.

The Problem

WordPress still uses an MD5 based password hashing scheme. They are effectively making 25% of websites more insecure because they refuse to bump their minimum PHP requirements. By continuing to allow EOL PHP versions back to 5.2, they can't use newer functions like password_hash.

This is a known problem which WordPress has ignored for over 4 years now. Not only does WordPress set the insecure default of MD5, they don't do any of the following:

  • document this issue
  • provide instructions on how to fix it and make it more secure
  • notify users on newer PHP versions that they could be more secure

What's wrong with MD5? Really simply: it's too cheap and fast to generate cryptographically secure hashes.

The Solution

WordPress did at least one good thing: they made wp_check_password and wp_hash_password pluggable functions. This means we can define these functions in a plugin and "override" the default ones.

This plugin plugs in 3 functions:

  • wp_check_password
  • wp_hash_password
  • wp_set_password

wp_hash_password

This function is the simplest. This plugin simply calls password_hash instead of WP's default password hasher. The wp_hash_password_options filter is available to set the options that password_hash can accept.

wp_check_password

At its core, this function just calls password_verify instead of the default. However, it also checks if a user's password was previously hashed with the old MD5-based hasher and re-hashes it with bcrypt. This means you can still install this plugin on an existing site and everything will work seamlessly.

The check_password filter is available just like the default WP function.

wp_set_password

This function is included here verbatim but with the addition of returning the hash. The default WP function does not return anything which means you end up hashing it twice for no reason.

FAQ

What happens to existing passwords when I install the plugin?

Nothing at first. An existing password is only re-hashed with bcrypt when they log in. If a user never logs in, their password will remain hashed with MD5 in your database forever.

Why doesn't this plugin re-hash all existing passwords in the database?

Right now it's beyond the scope of the plugin. We want to keep it simple and straightforward. This is probably best left up to the individual developer or maybe a separate plugin in the future. See #6 for more details.

What happens if I remove/deactivate the plugin?

Magically, everything still works. See this comment for more details.

Any existing bcrypt hashed passwords will remain that way. Any new users or users resetting a password will get a new MD5 hashed password.

Why aren't you using the password_compat library so this works back to PHP 5.3.7?

The password_compact library is great if you really need it. But the Roots team advocates using supported versions of PHP which of now (March 2016) is 5.5 and above. Part of security is using a version of PHP that still gets security patches so we won't actively do something to support old unsupported versions of PHP.

Why doesn't this plugin show up in the admin?

If you're using Composer, then the wp-password-bcrypt.php file is automatically autoloaded. It's not treated as a true WordPress plugin since the package type is not set to wordpress-muplugin so it won't show up in the plugin list.

What's wrong with using this as a plugin instead of a must-use plugin?

As explained above, you don't want to disable this plugin once you've enabled it. Installing this in plugins (as a "normal" plugin) instead of in mu-plugins (as a must-use plugin) makes it possible for an admin user to accidentally disable it.

How is this different than other plugins which already exist?

There are a few plugins that exist which enable bcrypt. This plugin is different because we bypass the PasswordHash class and the phpass library that WordPress core uses. This plugin uses PHP's built-in password_hash and password_verify functions directly to only support PHP 5.5+.

I already use Two-factor authentication and/or prevent brute-force login attempts. Does this plugin still help?

Better hashing functions like bcrypt serve a different purpose than Two-factor authentication, brute-force attempt protection, or anything which acts at the log in stage. Strong hashing functions are important if an attacker is able to get access to your database. They will make it much harder/practically impossible to determine the plain-text passwords from the hashes. Whereas with MD5, this is trivial. Tools/plugins to protect logging in are still important and should be used together with this plugin.

Further Reading

Contributors

This plugin is based on a Gist by @Einkoro.

It has been modified and packaged by the Roots team. Jan Pingel (@Einkoro) has granted his permission for us to redistribute his original BSD-licensed code to an MIT license.

Contributing

Contributions are welcome from everyone. We have contributing guidelines to help you get started.

Community

Keep track of development and community news.

wp-password-bcrypt's People

Contributors

dr5hn avatar mckernanin avatar michaelbeil avatar paultibbetts avatar qwp6t avatar retlehs avatar swalkinshaw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wp-password-bcrypt's Issues

Error: Maximum execution time of 30 seconds exceeded

Description

We're seeing timeouts related to wp_check_password().

Since we're running on Heroku, we can't increase the timeout of 30s.

We're also not seeing a stacktrace, just this:

Sentry\Exception\FatalErrorException: Error: Maximum execution time of 30 seconds exceeded
#0 /vendor/roots/wp-password-bcrypt/wp-password-bcrypt.php(42): null

Login and everything else works fine. We don't know what's actually failing.

Removing the plugin afterwards

What if I remove the plugin later? The passwords would not convert into md5, so users wouldn't be able to log in, right?!

Cannot redeclare wp_check_password()

Fatal error: Cannot redeclare wp_check_password() (previously declared in C:\Users\johh-smith\Documents\Websites\test.dev\wp-includes\pluggable.php:2087) in C:\Users\john-smith\Documents\Websites\test.dev\wp-content\plugins\wp-password-bcrypt\wp-password-bcrypt.php on line 44

Just tried activating it on a local dev site using Desktop Server.

Feature Request: Please address this plugin's conflicts with `php-stubs/wordpress-stubs`

Terms

Summary

It is currently not possible to use phpstan with phpstan-wordpress and the wordpress-stubs packages when installing roots/wp-password-bcrypt via composer.json without resorting to some very hacky (and unreliable/repetitive/frustrating) workarounds.

The full issue is described in szepeviktor/phpstan-wordpress#41.

Motivation

Why are we doing this?

To reduce the frustration of working with WordPress, to improve compatibility, and to facilitate reproducible development tasks in local and CI workflows.

Please read:

I am aware this has been mentioned indirectly in the past, but it appears that there has been little consideration given to making a change in this plugin despite the numerous accounts over the years. I am referring specifically to #11, but there are other examples.

It would be great if roots/wp-password-bcrypt could find a way to improve compatibility with these other libraries, because both this plugin and those libraries have been positive improvements to the WordPress ecosystem that unfortunately do not mix well.

What use cases does it support?

What is the expected outcome?

Developers and CI pipelines should be able to run phpstan analyse when this plugin is installed via composer.json and the WordPress stubs are loaded without any conflict.

I encourage the authors of this plugin to listen to the feedback from other developers who have encountered such conflicts and have given specific suggestions as to a fix.

For example:

Check if function exists in wordpress-stubs.php · Issue #70 · php-stubs/wordpress-stubs

I've given a couple of workshops on WordPress+PHPStan and both times this exact problem was the first to arise. We determined that the most correct solution is for the Bedrock bcrypt library to wrap its functions in function_exists() checks because it has no way to ensure that another definition of one of those functions isn't loaded by another plugin. I'm not sure why that is not the case.

Potential conflicts / foreseeable issues

Unknown. I am only a user of both tools reporting my experience and, more importantly, linking the two GitHub issues together because it looks like there's only been isolated conversations in each repo about this issue.

Additional Context

No response

Feature Request: Allow Plugin to Be Installed as a MU Plugin via Composer

Terms

Summary

Instead of only being able to install the plugin as a MU Plugin manually it would be nice to be able to install it that was via Composer since the WordPress Composer installers allow for this. I have my own working example of doing this here: https://github.com/ndigitals/wp-local-media-proxy/blob/main/composer.json

Specifically adding

"type": "wordpress-muplugin",

and leveraging the boxuk/wp-muplugin-loader Composer package works. Though I believe you may have your own MU Plugin loader.

Motivation

Why are we doing this?

Allow for installing as a MU Plugin but also keep it managed as a package dependence so that Composer sites can still update the package.

What use cases does it support?

There is an aspect where this package breaks PHPStan checks when used along with WordPress stubs. This is due to this package conflicting with Core functions and autoloading. However, the additional use case is to also be able to clearly see when review the Site Health tools in the Dashboard that this MU Plugin is actually running on the site. With the current Composer installation it's hidden and not obvious to general site support.

What is the expected outcome?

This can be installed as a MU Plugin and loaded, doesn't conflict with PHPStan execution with WordPress Stubs, is accurately reflected in the WordPress Dashboard Site Health.

Potential conflicts / foreseeable issues

Which MU plugin autoloader to use it a question. There is a generally available Composer package that can be used but there also seems to be a non-Composer based one that Bedroock/Roots uses for it's own stuff. This doesn't work well for non-Bedrock sites.

Additional Context

No response

Implement needs verify

It may be a good practice to implement password_needs_rehash by default.

Since we're using PASSWORD_DEFAULT and relying on the default cost option, PHP can update these in the future. If that happens and the plugin doesn't change, hashing would be broken. This is a very long term potential problem, but it could happen.

If we always check for password_needs_rehash then we can future proof against this.

Other options:

  • Hardcode PASSWORD_BCRYPT to avoid this
  • Hardcode the default cost option?
  • Leave this up to the users and document how they could implement password_needs_rehash

Cannot redeclare wp_check_password()

I saw that #7 has already come and gone but I have just experienced this in a different situation.

I have a dev box running PHP Version 5.5.9-1ubuntu4.11 according to phpinfo().

I installed the plugin by downloading the master.zip from github and extracting to the correct plugins folder.

When I activated it I saw this error:

Fatal error: Cannot redeclare wp_check_password() (previously declared in /srv/www/basetemplate/htdocs/wp-includes/pluggable.php:2087) in /srv/www/basetemplate/htdocs/wp-content/plugins/wp-password-bcrypt/wp-password-bcrypt.php on line 24

I'm not using the mu stuff, I didn't use composer, I did renamed the folder to remove the -master, I am using the latest Sage as the theme.

I'm locked out of my account

I have a local installation of WP with Bedrock and I can't reset my password.

  1. My local server can't send emails (so I can't reset my password in a normal way);
  2. I've tried modifying my password from PhpMyAdmin using MD5 checksum, but that didn't work (I couldn't log in with the new password);
  3. I've tried modifying my password from PhpMyAdmin by entering already encrypted password using this tool: https://passwordhashing.com/BCrypt?plainText=123456 and that didn't work either.

I am basically locked out of my website. What can I do to reset my password?

Bug: Fatal error: Cannot redeclare wp_check_password() (../wp-password-bcrypt/wp-password-bcrypt.php on line 29

Terms

Description

What's wrong?

Fatal error: Cannot redeclare wp_check_password() (../wp-password-bcrypt/wp-password-bcrypt.php on line 29

Cant get it to work, I have had no problems either adding it in Code Snippets, or as a regular plugin.

I have built myself a solution to prevent deleting, and deactivating selected plugins so I dont need to have this as a mu-plugin. This let me update the plugin at scale through wp managing solution.

Still doesnt work though

I took the wp-password-bcrypt.php file and pack it down to a zip file and uploaded as a plugin, and it wont activate due to the error above.

It is simply not fun to update client site one by one in case it updates in the future. Uploading a plugin for bulk update across all sites is such a time saver.

And yes, I've seen that the problem have occured before in this Github rep and in the forum, but isn't there a solution available?

Thank you for reading!

Steps To Reproduce

See earlier field.

Expected Behavior

See earlier field.

Actual Behavior

See earlier field.

Relevant Log Output

No response

Versions

Latest on everything (PHP, bcrypt and wp)

Cannot redeclare wp_check_password()

Bug report

Please provide steps to reproduce, including full log output:

Occurs each time I attempt to go to my plugins page. I am unable to access my plugins page. Each time I do I receive this in my logs:

PHP Fatal error: Cannot redeclare wp_check_password() (previously declared in /xxxxx/xxxxx/xxxxx/wp-includes/pluggable.php:2126) in /xxxxx/xxxxx/xxxxx/wp-content/mu-plugins/wp-password-bcrypt.php on line 24

Please describe your local environment:

wp-password-bcrypt version: 1.0

WordPress version: 4.8.2

Where did the bug happen? Development or remote servers?

Remote servers

Please make this available in the main WordPress plugins directory

This is a fantastic plugin but I worry that it will be criminally under used because it's not in the main WordPress plugins directory:

As far as I can tell this is because in the roots ecosystem you consider doing everything via Composer as the normal / best way to do it, plus your concerns about someone disabling the plugin:

As explained above, you don't want to disable this plugin once you've enabled it. Installing this in plugins (as a "normal" plugin) instead of in mu-plugins (as a must-use plugin) makes it possible for an admin user to accidentally disable it.

If you add it to the WordPress plugins directory then:

  1. It makes it much easier for people to install - the vast majority of WordPress users don't use Composer
  2. Any security updates you make for this will be automatically highlighted to users

Surely the point of this plugin is to help all WordPress users improve their security? The risk that some admins will disable the plugin (which would be odd when it's likely that they would have been the ones to install it), seems relatively smaller than the benefits.

Perhaps there's some other restrictions on the WordPress plugins directory that I don't know about.

Migrate from wp-bcrypt

You mention other plugin in the FAQ. It would be nice to know if the wp-bcrypt plugin can be swapped with this one without affecting current user logins. I've been running the wp-bcrypt plugin plugin for at least a few years now and have thousands of users on my site so It would be great to switch to a plugin that is supported.

Increase security of existing MD5 passwords

When installing this plugin the passwords of existing users are still stored as an MD5 hash. When the user logs in, there is a check to see if they have a legacy MD5 hash, and if so (upon successful authentication) the provided value will be used to 'upgrade' it to a bcrypt hash.

This on it's own doesn't do much to increase security, as until the user logs in their password will still be stored as an MD5 hash. Depending on how often users log in, it may be a very long time (think membership / community sites) until a secure bcrypt hash is stored for every user. If the database is compromised, you will still be leaking MD5 hashes which for simple passwords are trivial to reverse.

A more secure option would be to run all the existing MD5 hashes through password_hash when the plugin is installed, so in affect you are storing bcrypt(md5(password)) - no more MD5. A legacy flag can be added as a prefix in the hash field, and then when authenticating you can check that, to see if it's a legacy password that the should be MD5'ed before being passed to password_verify. At that point, once you have authenticated the user, you can generate a plain bcrypt hash so just bcrypt(password) is stored.

This is explained further, with example PHP code, in this Reddit post (not mine):

https://www.reddit.com/r/PHP/comments/3lwxlw/hash_and_verify_passwords_in_php_the_right_way/cva6y6p

Bug: unexpected behavior when calling wp_set_password() via REST API

Terms

Description

What's wrong?

Trying to change user password within a custom REST API route by calling wp_set_password() doesn't seem to do anything at the moment.

What have you tried?

Among other things tried disabling wp-password-bcrypt, after which things started working again.

What insights have you gained?

If I disable "application_password_is_api_request" check by filter (add_filter('application_password_is_api_request', '__return_false')) before calling wp_set_password() in my REST route, changing password seems to work as expected.

Possible solutions

Not familiar enough with the implementation to make any real suggestions, except that if this can't be reliably fixed, then perhaps it should be documented?

Temporary workarounds

Calling add_filter('application_password_is_api_request', '__return_false') before wp_set_password() in REST route.

Steps To Reproduce

  1. Create a REST API route and add call to wp_set_password('some-password-string', 1):
add_action( 'rest_api_init', function () {
	register_rest_route( 'my-namespace', '/pass-test', [
		'methods' => 'GET',
		'permission_callback' => '__return_true',
		'callback' => function( \WP_REST_Request $request ) {
			// add_filter( 'application_password_is_api_request', '__return_false' );
			wp_set_password( 'new-pass-here', 1 );
		},
	]);
});
  1. Call aforementioned REST API route
  2. Try to log in with new password

Expected Behavior

New password should work.

Actual Behavior

New password doesn't work, but old password still works. If I uncomment the filter in the action hook above, things now work as expected.

Relevant Log Output

No response

Versions

1.1.0

Password resets when paired with Application Passwords

Bug Report

Replace any X with your information.


What is the current behavior?

X When using this package paired with https://github.com/georgestephanis/application-passwords a users password (hash) is reset after every request using the app password.

What is the expected or desired behavior?

X A users password is not reset when making a basic auth request w/ the app password.


Bug report

(delete this section if not applicable)

Please provide steps to reproduce, including full log output:

  • Install the Application Password plugin.
  • Add an app password to your user (via your profile).
  • Make an API request with no-auth and notice no change.
  • Make an API request with your username and app password to any endpoint, and notice you're logged out of the WP admin, and your password hash has updated.

Please describe your local environment:

wp-password-bcrypt version: 1.0.0

WordPress version: 4.9.8

Active theme: twentyseventeen

Active plugins: application password

Where did the bug happen? Development or remote servers?

local & remote.

Please provide a repository or your wordpress_sites config (if possible):

N/A

Is there a related Discourse thread or were any utilized (please link them)?

No

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.