Introduce kernel parameters allowing to specify password hashing algorithm and options

Created on 14 June 2025, 2 months ago

Problem/Motivation

The constructor of the PhpPassword hashing class accepts two optional parameters for the algorithm and hashing options. These parameters were chosen to match the PHP password_hash() parameters.

However, the function signature changed a couple of times before and after the original issue went in ( πŸ“Œ Replace custom password hashing library with PHP password_hash() Fixed ). Especially the $algo paramater only became nullable with PHP 8.0. For lower versions it had to be specified explicitly. At the time when the original issue went in, it was unpractical to expose the $algorithm constructor parameter as a kernel parameter. Simply because the default is a PHP constant, and that directly encoded the default algorithm as a string.

Since the $algo parameter is nullable nowadays, it is possible to expose the password hashing algorithm as a kernel parameter (null by default). This makes it easier for contrib and custom code to switch it to something else.

Steps to reproduce

Proposed resolution

Modify the constructor of PhpPassword to make the $algorithm parameter nullable, parameter references to the @password@ service definition and add two new kernel parameters:

  password.algorithm: ~
  password.options: []

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

✨ Feature request
Status

Active

Version

11.0 πŸ”₯

Component

base system

Created by

πŸ‡¨πŸ‡­Switzerland znerol

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @znerol
  • πŸ‡¨πŸ‡­Switzerland znerol
  • Pipeline finished with Failed
    2 months ago
    #522378
  • πŸ‡¨πŸ‡­Switzerland znerol
  • πŸ‡¨πŸ‡­Switzerland znerol
  • Pipeline finished with Failed
    2 months ago
    #522420
  • Pipeline finished with Failed
    2 months ago
    #522421
  • πŸ‡¨πŸ‡­Switzerland znerol

    Postponing on #3530235

  • πŸ‡«πŸ‡·France andypost

    CI images has both now

  • πŸ‡«πŸ‡·France andypost

    constructor only changes looks ok but it require container rebuild so needs update hook to request it, otherwise looks ready

  • πŸ‡¨πŸ‡­Switzerland znerol

    Thanks! Added an update hook.

  • Pipeline finished with Success
    2 months ago
    Total: 673s
    #524011
  • πŸ‡«πŸ‡·France andypost

    Thank you! CR is ready and the code too

  • πŸ‡¬πŸ‡§United Kingdom longwave UK

    Looks good to me, added a question about the update hook though.

  • πŸ‡¨πŸ‡­Switzerland znerol
  • Pipeline finished with Success
    about 1 month ago
    Total: 835s
    #541920
  • πŸ‡ΊπŸ‡ΈUnited States benjifisher Boston area

    Thanks for working on this issue. As I said on πŸ“Œ Properly handle that PHP bcrypt passwords are truncated to 72 bytes Active ,

    • I think this issue is the right way to go. Let's make it easy to use something other than bcrypt.
    • I think we should implement hook_requirements. We could do that as part of this issue or on #3536662.

    @longwave mentioned #2951046 to me. I am adding that as a related issue. Once that issue gets in, we can use something like !php/const PASSWORD_ARGON2ID in services.yml.

  • The Needs Review Queue Bot β†’ tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

    This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

    Consult the Drupal Contributor Guide β†’ to find step-by-step guides for working with issues.

  • πŸ‡¨πŸ‡­Switzerland znerol
  • Pipeline finished with Success
    12 days ago
    Total: 670s
    #565852
  • πŸ‡«πŸ‡·France andypost

    I think requirements exposition of available hashes should be done in πŸ“Œ Properly handle that PHP bcrypt passwords are truncated to 72 bytes Active

    This issue exactly about to add support of argon and make it configurable, also soduim open doors to fast encrypted storage

  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    Left a minor question on the MR, fine to self RTBC

  • Pipeline finished with Success
    10 days ago
    #567599
  • πŸ‡¨πŸ‡­Switzerland znerol
    % ./vendor/bin/drush updb
     -------- ------------------ ------------- ------------------------------------
      Module   Update ID          Type          Description
     -------- ------------------ ------------- ------------------------------------
      system   password_kernel_   post-update   Rebuild the container after adding
               parameters                       new kernel parameters.
     -------- ------------------ ------------- ------------------------------------
    
    
     β”Œ Do you wish to run the specified pending updates? ───────────┐
     β”‚ Yes                                                          β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    >  [notice] Update started: system_post_update_password_kernel_parameters
    >  [notice] Update completed: system_post_update_password_kernel_parameters
     [success] Finished performing updates.
    
  • πŸ‡ΊπŸ‡ΈUnited States akalata
  • πŸ‡ΊπŸ‡ΈUnited States drumm NY, US
  • πŸ‡ΊπŸ‡ΈUnited States neclimdul Houston, TX
  • πŸ‡ͺπŸ‡ͺEstonia ram4nd Tallinn
  • πŸ‡ΊπŸ‡ΈUnited States xjm
  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    @catch mentioned on slack

    don't think we need the empty post update on 3530186 because the default deployment identifier is based on \Drupal::version() and that's used in the container cache key. Doesn't really matter except it's less updates to remove when the time comes later. Mentioning in here because it went around a couple of times in the issue already

    Sorry for the runaround @znerol - can we remove that?

    We discussed this on the security team triage call in relation to πŸ“Œ Properly handle that PHP bcrypt passwords are truncated to 72 bytes Active - in particular that issue's reintroduction of the legacy phpass hashing for users with passwords longer than 72 bytes where the bcypt algorithm is in use.

    We decided we would instead prefer to move forward with this issue rather than what is effectively backwards with the reuse of phpass.

    We decided we would prefer to have the hook_requirements from that issue added here that:

    1. Shows a warning if the site only has bcrypt hashing available - detailing the 72 char/null byte risk with links to PHP.net regarding argon2
    2. Shows an error if the site has argon2 available but it isn't the default hashing algorithm

    I've manually tested that changing the hashing algorithm with existing users successfully rehashes their password in the new algorithm when they next login.

    I will mark the other issue as postponed on this one in the meantime.

    We also decided to re-purpose the php_password contrib module as a BC layer as the changes in this MR can't be backported.

    So this issue here will fix 11.3/10.6 and the contrib module will decorate the core service to bring this functionality to stable branches. The contrib module will have a forward compatibility layer that will be a no-op if it detects the container param added here - which would indicate the module is no longer needed as the site has updated to a version with this feature.

    With this issue and the contrib module ready, we will likely issue a PSA

    Crediting those involved in the discussion.

  • πŸ‡«πŸ‡·France andypost

    Removed post update hook

  • Pipeline finished with Success
    9 days ago
    Total: 735s
    #568474
  • πŸ‡¬πŸ‡§United Kingdom catch

    I think this needs:

    We decided we would prefer to have the hook_requirements from that issue added here that:

    Shows a warning if the site only has bcrypt hashing available - detailing the 72 char/null byte risk with links to PHP.net regarding argon2
    Shows an error if the site has argon2 available but it isn't the default hashing algorithm

    from #24.

  • πŸ‡¦πŸ‡ΊAustralia larowlan πŸ‡¦πŸ‡ΊπŸ.au GMT+10

    forwards compatibility layer is ready for review here https://git.drupalcode.org/project/php_password/-/merge_requests/6/diffs

  • πŸ‡¨πŸ‡­Switzerland znerol

    Added the requirement checks.

    Should we add a config and a proper UI to make these requirement checks more actionable? Maybe an additional Password fieldset in admin/config/people/accounts?

  • Pipeline finished with Failed
    6 days ago
    Total: 765s
    #570034
  • Pipeline finished with Success
    6 days ago
    Total: 433s
    #570061
  • πŸ‡¨πŸ‡­Switzerland znerol
  • πŸ‡«πŸ‡·France andypost

    I think transition to new hash should be done in follow-up, moreover old passwords makes no sense when Argon2 available

  • Status changed to Needs review 4 days ago
  • πŸ‡ΊπŸ‡ΈUnited States benjifisher Boston area

    @andypost:

    What transition do you mean?

    Passwords should be rehashed automatically when users log in with their passwords. The Q&A for the Password Compatiblity module β†’ apply to this situation, too.

    From #24 here:

    I've manually tested that changing the hashing algorithm with existing users successfully rehashes their password in the new algorithm when they next login.

    @znerol:

    Should we add a config and a proper UI to make these requirement checks more actionable?

    I have been thinking that this is something that would be managed through settings.yml, not the UI. In fact, I like the idea of relying on something in the filesystem. Otherwise, XSS can be exploited to change the password hashing algorithm.

    If you still want to provide a configuration form, then let's have a followup issue for further discussion.

  • πŸ‡¨πŸ‡­Switzerland znerol

    By the time this ships, every single site which upgrades will generate a requirements warning. The requirements warning points to a CR which contains example code for a service provider class. The example code for the service provider class is there because I think we shouldn't instruct people to manually add a container parameter for this. The reason I think so is that it is safer to use the \PASSWORD_* constants instead of let people attempt to hard code the exact password algorithm into a yml file by hand.

    Regarding the UI: This could be just a password_argon2 module with its own requirements check and a service provider which adds the password.algoritm: argon2id container parameter.

  • πŸ‡ΊπŸ‡ΈUnited States benjifisher Boston area

    How is it easier to use the \PASSWORD_* constants? Using drush php:

    > password_algos()
    = [
        "2y",
        "argon2i",
        "argon2id",
      ]
    

    I think we should let people set a hashing algorithm in services.yml.

    Have we considered what to do if the service parameter is invalid? Do we fall back to PASSWORD_DEFAULT? Is there a requirements check (for the status page)?

  • πŸ‡¨πŸ‡­Switzerland znerol

    In the MR. There is a requirements check for unknown / misspelled password algorithms.

    When an algorithm is configured which isn't available on the system, attempting to create new password hash will result in a fatal:

    Fatal error: Uncaught ValueError: password_hash(): Argument #2 ($algo) must be a valid password hashing algorithm in Command line code on line 1

    Verifying existing hashes still works (assuming the hashing algorithm is available on the system).

  • Pipeline finished with Failed
    3 days ago
    Total: 127s
    #573608
  • Pipeline finished with Success
    3 days ago
    Total: 412s
    #573624
Production build 0.71.5 2024