Vanilla 1 is no longer supported or maintained. If you need a copy, you can get it here.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.

Vanilla password security

2

Comments

  • That's perfect.

    the db will still have old md5 hash, but we can leave for Vanilla 1.1.6 or for an extension the job to delete all old md5 hash.
  • you mean the md5 hashes of users that haven't logged in since the update? just making sure b/c the point of this is that it will update passwords in place.
  • yep, it is what I meant
  • edited September 2008
    Here's my patch. I made it as low-impact as possible, with as little room as possible for introducing new bugs. It's based on 1.1.5 RC2 because I didn't have Dinoboff's revamped version, but honestly I think this is the best way to go.

    No modification to phpass, no wrapper around it. Pulls all password checking and updating code into the Authenticator class where it belongs. Passwords are updated in place when users log in. Keeps compatibility with (very old) plaintext passwords.

    It uses the portable (md5-based) hashes instead of Blowfish. I know I said a bunch of stuff about how awesome Blowfish is but Dinoboff is right, we can't count on it. The phpass md5 hashes are still many orders of magnitude better than what we use now.

    Execute the following command in your vanilla-1.1.5-rc2 directory:
    patch -p1 < phpass.diff

    I haven't tested in at all yet. Sorry about the inevitable typos.
    http://www.digitalsquirrel.com/vanilla/phpass.diff
  • Put up a new version that actually works. Fun!

    http://www.digitalsquirrel.com/vanilla/phpass.diff
  • edited September 2008
    I removed the hash class wrapper, but like my previous patch I removed all the sql stuff from Authenticator.

    I also wrote an upgrader. Check the end of appg/settings.php. I couldn't find a better place for it.

    Try the last version:
    http://dl.getdropbox.com/u/83967/vanilla-1.1.5-revamped-security.zip
  • Do you have a diff of just the password-related changes? There are a lot of changes from rc2 to this zip and it's hard to tell which are specifically password related. One problem I can see is People.Class.PasswordHash.php. I don't think it's a good idea to make modifications to the phpass code. It's not necessary, it risks introducing bugs to code that we didn't write and it will make it more difficult to drop in any future revision of phpass. On the whole it's a much more extensive modification than I was thinking of. I know I've been advocating this change for 1.1.5 but I was hoping we could do it more surgically.
  • Or maybe we can't, since you just released RC3 with all of these changes rolled in. Am I missing something? What's the big rush here? Shouldn't we take some time to talk about this?
  • edited September 2008
    Since I changed the protocol of the UserManager and Authenticator classes, it should probably only be added to Vanilla 1.2 or the call to the authenticator from the user manager should be copied to the user manager (and removed in 1.2) and vice-versa.

    For the modifications to PasswordHash, they are just in the constructor, they would be easy to track. I could just extends it. But since I wasn't sure the settings are that useful (Can you change the settings after some password has been created?) I might just remove them.
  • 1.1.5 should have been release 2 weeks ago. We pushed it back one week ago just for this fix.

    I released rc3 to get feedback. Thanks to subversion (TortoiseSVN), changes are very easy to roll back.
  • edited September 2008
    Here are the diffs between 1.1.4 and 1.1.5-rc3: http://dl.getdropbox.com/u/83967/framework.diff http://dl.getdropbox.com/u/83967/people.diff - most of it is related to password storage change. http://dl.getdropbox.com/u/83967/vanilla.diff
  • If it's that important to release 1.1.5 then just release it. It's not my call. I gave my opinion on what should happen, I obviously don't control the final result.

    I still haven't heard why it's so important to get 1.1.5 out by a specific date, but again, it's not my decision to make.

    I appreciate the diffs but they're not what I asked for. I'm trying to figure out what changes were made just for the password issue since that issue has had less testing than anything else.

    I want to help but I have no idea what's going on here. Last week you didn't even want this change in 1.1.5. I understand the issue of making a change like this so close to a release so I tried to propose a patch with as few code changes as possible. But a few days later and now we're reviewing what looks like a complete overhaul of the Authenticator class with half of its functionality shifted to the UserManager class.

    Where is this coming from? It wasn't the fix I suggested. What makes this the best fix for 1.1.5?
  • You gave me a diff with an outdated version of People. I removed the wrapper like you suggested but didn't add the extra argument on the authenticator method, instead I added a method to check the password. If someone use an outdated version of Authenticator, it will fail instead of having the UserManager doing extract stuff when it should have just check the password.
  • It wasn't outdated, it was based on RC2. RC2 was the version you were preparing to release as final as of August 30. I proposed it as an alternative to your "vanilla-1.1.5-revamped-security.zip" because it's a smaller patch with fewer changes to review.

    I wasn't worried about custom Authenticators because I didn't think they were officially supported. When did that change?
  • edited September 2008
    There are not supported but the methods and the signatures they are suppose to support are:
    - Authenticator::Authenticate($Username, $Password, $PersistentSession)
    - Authenticator::DeAuthenticate()
    - Authenticator::GetIdentity()

    Vanilla expect them and no more. (I think it should also manage the creation and modification of the credentials, instead of having them in the UserManager; UserManager for the credentials part should only be responsible of saving them in the user table - in the case on the default authenticator).

    Sirnot's patch, yours and mine change them or add some methods and it could affect some forum.
  • Okay, that's fair. In that case I suggest we patch phpass into the following four functions:

    Authenticator::Authenticate()
    UserManager::ChangePassword()
    UserManager::CreateUser()
    UserManager::ResetPassword()

    If the goal is to fix the password encoding, do it as gently as possible. It can be done without making this change to ObjectFactory which has nothing to do with password encoding. If you're going to drop changes like that between release candidates then please don't tell me that 1.1.5 is being pushed back "just for this fix".

    I like the changes you're proposing to Authenticator and UserManager but they are way, way more than what is needed to fix this issue.
  • Here is the diff between r108 (rc2) and r115 of people: http://dl.getdropbox.com/u/83967/people-diff-108-115.diff I removed the modification to PasswordHash and moved all modifications of the Authenticator protocol to the UserManager.
  • Won't this break custom Authenticators even more? How can you authenticate users against, say, a WordPress user table if the password comparison is only being done in UserManager?
  • edited September 2008
    The comparison of the password is only a method shared by Authenticator::Authenticate(), UserManager::ChangePassword() and UserManager::ResetPassword(). Since we can't really change the Authenticator interface (not in Vanilla 1.1.x), I put them in the UserManager. Authenticators that will get broken are the one that use Vanilla password but need the authenticator to do extra-stuff. I don't see any way to avoid it. It wouldn't have been a problem if the authenticator had also been managing the change and reset of the password or if UserManager::ChangePassword() and UserManager::ResetPassword() had been using Authenticator::Authenticate() for the authentication part of their job. To not break any installation we could add a setting to turn on the new storage; Change the Authenticator interface in Vanilla 1.2 and then have the new storage on by default.
  • edited September 2008
    Maybe UserManager::ChangePassword() and UserManager::ResetPassword() should still save a md5 hash and only let the authenticator regenerate it?

    With the following changes they would only save the password with the new hash method if the authenticator has been updated:
    Index: People.Class.Authenticator.php =================================================================== --- People.Class.Authenticator.php (revision 115) +++ People.Class.Authenticator.php (working copy) @@ -130,6 +130,14 @@ return $UserID; } + function HashPassword($Password) { + $PasswordHash = $this->Context->ObjectFactory->NewObject( + $this->Context, 'PasswordHash', + $this->Context->Configuration['PASSWORD_HASH_ITERATION'], + $this->Context->Configuration['PASSWORD_HASH_PORTABLE']); + return $PasswordHash->HashPassword($Password); + } + // All methods below this point are specific to this authenticator and // should not be treated as interface methods. The only required interface // properties and methods appear above. Index: People.Class.UserManager.php =================================================================== --- People.Class.UserManager.php (revision 115) +++ People.Class.UserManager.php (working copy) @@ -579,12 +579,19 @@ return $this->Context->Database->Select($s, $this->Name, 'GetUserSearch', 'An error occurred while retrieving search results.'); } + /** + * Create a password hash. + * + * @deprecated + * @param string $Password + * @return string + */ function HashPassword($Password) { - $PasswordHash = $this->Context->ObjectFactory->NewObject( - $this->Context, 'PasswordHash', - $this->Context->Configuration['PASSWORD_HASH_ITERATION'], - $this->Context->Configuration['PASSWORD_HASH_PORTABLE']); - return $PasswordHash->HashPassword($Password); + if (method_exists($this->Context->Authenticator, 'HashPassword')) { + return $this->Context->Authenticator->HashPassword($Password); + } else { + return md5($Password); + } } function GetSearchBuilder($Search) {
This discussion has been closed.