
Notice of Security Incident - captn3m0
https://about.flipboard.com/support-information-incident-May-2019/
======
CiPHPerCoder
> If users created or changed their password after March 14, 2012, it is
> hashed with a function called bcrypt. If users have not changed their
> password since then, it is uniquely salted and hashed with SHA-1.

This is a common mistake.

Don't ever do _opportunistic_ upgrades. Instead, upgrade all at once and
retain "legacy" metadata needed to re-authenticate the user until their
password hash is rotated. [https://paragonie.com/blog/2016/02/how-safely-
store-password...](https://paragonie.com/blog/2016/02/how-safely-store-
password-in-2016#legacy-hashes)

Beyond that: Bcrypt is great, SHA1 is terrible, and the level of technical
detail in this advisory is excellent. The fact that I was even able to
critique their 7 years old security decision _at all_ speaks volumes to the
transparancy.

~~~
moloch
I think their main mistake was requiring a user to change their password to
upgrade the hash instead of upgrading the hash on the next user login.

~~~
CiPHPerCoder
What if there wasn't a "next user login"? You'd hold onto insecure hashes
possibly forever.

Don't make this mistake. Rehash all of them up front.

The details of whether or not users are forced to change their password is
irrelevant to the escape route from this trap.

~~~
nameismypw
How are you going to rehash them without having the cleartext password? Hash
the SHA1s to bcrypt and then check every password's bcrypt and SHA1*bcrypt's
password from then on?

~~~
msbarnett
It’s explained in the linked blog post in the chain you’re replying to, but:

\- Set all password hashes to Bcrypt(existing SHA-1 Hash)

\- Create a new flag column to track whether the password is upgraded to
straight Bcrypt.

\- If flag is false, compare stored hash with Bcrypt(SHA-1(user input)). If it
matches, log user in and replace stored hash with Bcrypt(user input). Set flag
true.

\- If flag is true, compare stored hash with Bcrypt(user input)

~~~
SahAssar
I don't think that'd work in this case since the SHA-1 was salted, so you'd
need to store the SHA-1 salt in a separate column, then calculate
Bcrypt(SHA-1(input + salt)), right?

~~~
msbarnett
Obviously they had to be storing the salt to begin with, so yes you’d keep
using that salt column and use user input+salt as the input to SHA-1.

------
winningcontinue
For an app that I no longer use, long since deleted and have forgotten about,
hearing that there was a security incident that compromised my password is
unsettling. I was relieved that I logged in to their app through twitter and
my password wasn't store through them.

~~~
kelnos
Same here, at least for the first part. I had used a plain email/password to
sign up. After getting this advisory I reset my password and immediately
deleted my account.

Nothing against Flipboard, and I appreciate the level of transparency here,
but it's annoying to think that I created that account 7 or 8 years ago,
haven't touched it since, and it's still there, with the potential to be a
liability to me.

------
ppierald
Bummer for the company and I wish them well as they navigate the incident
response waters. What I found interesting from the article was

If users created or changed their password after March 14, 2012, it is hashed
with a function called bcrypt. If users have not changed their password since
then, it is uniquely salted and hashed with SHA-1.

They could have migrated all accounts regardless of whether they came back to
the site or not, changed their password or not, etc. Just use:

password_hash = bcrypt(sha1(raw_password))

------
earblast
What can someone use as a salt that is unique to a user that would not be in
that record as plain-text and guess-able? Creation timestamp? email? username?

~~~
c22
Just use a random value and store it with the hashed password. The salt is
there to prevent an attacker from using a rainbow table to search your whole
database for known passwords. Even if they have all your hashes and all your
salts the fact the salts are unique forces them to attack each hash
individually.

What you're looking for is a pepper [0]

[0]
[https://en.wikipedia.org/wiki/Pepper_(cryptography)](https://en.wikipedia.org/wiki/Pepper_\(cryptography\))

~~~
earblast
Hmm, seems to me using both is optimal

horrible psuedocode follows...

    
    
      cryptchoice = len(username) % 3
    
      switch cryptchoice:
         case 0:
           pepper = pepper[1]
           salt = email
    
         case 1:
           pepper = pepper[0]
           salt = creation_time
           
         case 2:
           pepper = pepper[2]
           salt = username
           
      bcrypt(salt+password+pepper)

~~~
c22
It's definitely wise to use both a salt and a pepper when hashing passwords.
Don't bother with the switch statement, though, it's just security through
obscurity. You're much better off keeping your security-related code as simple
as possible so it's easier to notice bugs in it.

------
danarel
This just made for a good reminder I needed to close this account.

