Uploaded image for project: 'Moodle'
  1. Moodle
  2. MDL-35332

Improve security of hashed passwords

    Details

    • Testing Instructions:
      Hide

      While testing you might want to run a query on the database to look at the format of the password field:

      > SELECT id, username, password FROM mdl_user;

      id username password
      3 testuser b0c1805f9b6435abbf6c2d3fe81ecb36

      if the password is of the form:

      b0c1805f9b6435abbf6c2d3fe81ecb36

      then it's the old-style md5 hash. If it looks more like:

      $2y$10$DzO4FuCYRFnx1wyiYiOI8udJA8yrALCYFnMyFOfX.ZbNLo6.VtV/y

      then it is in the new (bcrypt) format

      Test functionality with PHP version that supports bcrypt (typically PHP 5.3.7 or above)

      Hashes updated on first login following upgrade

      1. Install a site without the patch applied
      2. Create some users with known passwords
      3. Upgrade site to include patch
      4. Login as some of the users (they should still be able to login)
      5. Log out and log back in again (they should still be able to login)
      6. Try to login as a user with the wrong password (should not be able to login)

      DB checks:
      After step 2 - old style hash
      After step 3 - same as step 2
      After step 4 - new style hash
      After step 5 - same as step 4

      e.g. the hash changes once when the user first successfully logs in

      New users created by admin

      1. Install a new site with the patch installed
      2. Create some users with known passwords
      3. Login as some of the users (they should be able to login)

      DB checks: password should always be the new format

      Self registration

      1. Create a site with patch applied
      2. As admin enable self-registration via Site Admin > Plugins > Authentication > Manage Authentication > Self registration
      3. Logout
      4. Create a user account (note: mail must be working on your site to test this)
      5. Test you can login with the password you provided

      DB checks: password should always be the new format

      Password change

      1. Create a site with patch applied
      2. Login as any user
      3. Click My Profile Settings > Change password and enter a new password
      4. Logout
      5. Check that you can login again with the new password

      DB checks: password should always be the new format

      Note: You will get a PHP Notice when changing passwords due to MDL-37515.

      Bulk upload with passwords specified

      1. Create a text file containing the following:
        firstname,lastname,username,email,password
        Test,User,testuser,test@example.com,abc123
      2. As an admin visit Site Admin > Users > Accounts > Upload Users
      3. Choose the file you created in step 1 and click upload users
      4. Under 'New user password' choose 'Field required in file'
      5. Click upload users
      6. Test user should be created
      7. Logout
      8. Login with testuser and password abc123
      9. You should be able to login
      10. Logout and log back in again

      DB checks:
      After step 5 - new hash starting '$2y$04$'
      After step 8 - new style hash starting '$2y$10$'
      After step 10 - same as step 8

      Bulk upload with passwords not specified

      1. Create a text file containing the following:
        firstname,lastname,username,email
        Test,User2,testuser2,test2@example.com
      2. As an admin visit Site Admin > Users > Accounts > Upload Users
      3. Choose the file you created in step 1 and click upload users
      4. Under 'New user password' choose 'Create password if needed'
      5. Click upload users
      6. Test user should be created
      7. Run the cron
      8. Check email, you should have received an email with a temporary password (note: mail must be working on your site to test this)
      9. Logout
      10. Login with testuser and password from the email
      11. You should be able to login. You will be prompted to change the password
      12. Change the password
      13. Logout and log back in again with the new password
      14. You should be able to log in

      DB checks:
      After step 5 - 'to be generated'
      After step 7 - new style hash starting '$2y$04$'
      After step 9 - new style hash starting '$2y$10$'
      After step 11 - same as step 9

      Test forgotten password functionality

      1. Create a new site with the patch applied
      2. Visit the login page (not logged in)
      3. Click "Forgotten your username or password?"
      4. Enter an existing username or password that you have access to the email of
      5. Click the confirmation link in your email
      6. Check your email again to get the new password
      7. Check you can login with the new password

      DB checks:
      After step 1 - new style hash
      After step 5 - new style hash, but different to before
      After step 7 - same as step 5

      Account access via non-caching auth plugin

      1. Create a new site with the patch applied
      2. Add the attached test auth plugin to auth/test/
      3. Visit the notification page to install
      4. Go to Site admin > Plugins > Authentication > Manage Authentication Plugins
      5. Enable the plugin
      6. Create a new user, assigning them the 'test auth' authentication type
      7. Logout
      8. Login as the test user (any password will work)
      9. The password should not be stored in the user table
      10. Logout and log back in as admin
      11. Change the users auth method to manual and set a password
      12. Logout and login as that user checking the password works
      13. Log back in as admin and switch back to the test auth plugin
      14. Log back in as the user with the same password
      15. Logout and back in as the user with a different password

      DB checks:
      After step 6 - 'not cached'
      After step 8 - same as step 6
      After step 11 - new style hash
      After step 14 - same as step 11
      After step 15 - 'not cached'

      Test functionality with PHP version that doesn't support bcrypt (typically 5.3.6 or below)

      Repeat the tests above making sure everything works - should continue
      to function as before but using only the old algorithm (md5)

      Note: Some distributions have backported bcrypt support to releases prior to 5.3.7.

      Show
      While testing you might want to run a query on the database to look at the format of the password field: > SELECT id, username, password FROM mdl_user; id username password 3 testuser b0c1805f9b6435abbf6c2d3fe81ecb36 if the password is of the form: b0c1805f9b6435abbf6c2d3fe81ecb36 then it's the old-style md5 hash. If it looks more like: $2y$10$DzO4FuCYRFnx1wyiYiOI8udJA8yrALCYFnMyFOfX.ZbNLo6.VtV/y then it is in the new (bcrypt) format Test functionality with PHP version that supports bcrypt (typically PHP 5.3.7 or above) Hashes updated on first login following upgrade Install a site without the patch applied Create some users with known passwords Upgrade site to include patch Login as some of the users (they should still be able to login) Log out and log back in again (they should still be able to login) Try to login as a user with the wrong password (should not be able to login) DB checks: After step 2 - old style hash After step 3 - same as step 2 After step 4 - new style hash After step 5 - same as step 4 e.g. the hash changes once when the user first successfully logs in New users created by admin Install a new site with the patch installed Create some users with known passwords Login as some of the users (they should be able to login) DB checks: password should always be the new format Self registration Create a site with patch applied As admin enable self-registration via Site Admin > Plugins > Authentication > Manage Authentication > Self registration Logout Create a user account (note: mail must be working on your site to test this) Test you can login with the password you provided DB checks: password should always be the new format Password change Create a site with patch applied Login as any user Click My Profile Settings > Change password and enter a new password Logout Check that you can login again with the new password DB checks: password should always be the new format Note: You will get a PHP Notice when changing passwords due to MDL-37515 . Bulk upload with passwords specified Create a text file containing the following: firstname,lastname,username,email,password Test,User,testuser,test@example.com,abc123 As an admin visit Site Admin > Users > Accounts > Upload Users Choose the file you created in step 1 and click upload users Under 'New user password' choose 'Field required in file' Click upload users Test user should be created Logout Login with testuser and password abc123 You should be able to login Logout and log back in again DB checks: After step 5 - new hash starting '$2y$04$' After step 8 - new style hash starting '$2y$10$' After step 10 - same as step 8 Bulk upload with passwords not specified Create a text file containing the following: firstname,lastname,username,email Test,User2,testuser2,test2@example.com As an admin visit Site Admin > Users > Accounts > Upload Users Choose the file you created in step 1 and click upload users Under 'New user password' choose 'Create password if needed' Click upload users Test user should be created Run the cron Check email, you should have received an email with a temporary password (note: mail must be working on your site to test this) Logout Login with testuser and password from the email You should be able to login. You will be prompted to change the password Change the password Logout and log back in again with the new password You should be able to log in DB checks: After step 5 - 'to be generated' After step 7 - new style hash starting '$2y$04$' After step 9 - new style hash starting '$2y$10$' After step 11 - same as step 9 Test forgotten password functionality Create a new site with the patch applied Visit the login page (not logged in) Click "Forgotten your username or password?" Enter an existing username or password that you have access to the email of Click the confirmation link in your email Check your email again to get the new password Check you can login with the new password DB checks: After step 1 - new style hash After step 5 - new style hash, but different to before After step 7 - same as step 5 Account access via non-caching auth plugin Create a new site with the patch applied Add the attached test auth plugin to auth/test/ Visit the notification page to install Go to Site admin > Plugins > Authentication > Manage Authentication Plugins Enable the plugin Create a new user, assigning them the 'test auth' authentication type Logout Login as the test user (any password will work) The password should not be stored in the user table Logout and log back in as admin Change the users auth method to manual and set a password Logout and login as that user checking the password works Log back in as admin and switch back to the test auth plugin Log back in as the user with the same password Logout and back in as the user with a different password DB checks: After step 6 - 'not cached' After step 8 - same as step 6 After step 11 - new style hash After step 14 - same as step 11 After step 15 - 'not cached' Test functionality with PHP version that doesn't support bcrypt (typically 5.3.6 or below) Repeat the tests above making sure everything works - should continue to function as before but using only the old algorithm (md5) Note: Some distributions have backported bcrypt support to releases prior to 5.3.7.
    • Affected Branches:
      MOODLE_21_STABLE, MOODLE_22_STABLE, MOODLE_23_STABLE, MOODLE_24_STABLE
    • Fixed Branches:
      MOODLE_25_STABLE
    • Pull from Repository:
    • Pull Master Branch:
      master_MDL-35332

      Description

      Currently moodle uses md5 for password hashing and a site-wide salt when hashing passwords. It's generally considered best practice to use a modern hashing algorithm like Bcrypt for password hashing, and to have per-user salts - e.g:

      https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet#Rule_1:_Use_a_Modern_Hash_Algorithm
      https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet#Rule_2:_Use_a_Long_Cryptographically_Random_Per-User_Salt

      Bcrypt is now available natively in PHP5.3 via the crypt() function. I thought I'd create this bug to gauge interest and perhaps kick off some work to implement this.

      Obviously this would need to be implemented in a backward compatible way. I would suggest something like:

      1. Add 'password_hash' and 'salt' columns to user table, initially set to null
      2. Add code to authenticate using bcrypt or similar (ideally using an existing library)
      3. Update code for creating users to use new method
      4. When a user logs in check if 'password_hash' is null
      4a. If null authenticate using md5 and password column then calculate new hash with salt and store in db
      4b. If not null authenticate using bcrypt and new data

      This would gradually migrate existing sites to the new algorithm (as users login) while allowing new sites to use bcrypt exclusively. For sites that want to migrate fully, the administrator could reset all 'old' passwords.

      There are bound to be some edge cases that will need to be considered, such as 'changeme' passwords, other authentication plugins, etc. I would appreciate any thoughts from anyone more familiar with moodle authentication.

      Simon

        Gliffy Diagrams

          Attachments

            Issue Links

              Activity

                People

                • Votes:
                  5 Vote for this issue
                  Watchers:
                  19 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved:
                    Fix Release Date:
                    14/May/13