standardnotes / forum

Support from other community members. For 1-on-1 help, please contact help@standardnotes.com.
https://forum.standardnotes.org
197 stars 9 forks source link

Technical Details on Security Update #54

Closed moughxyz closed 1 year ago

moughxyz commented 7 years ago

We sent out an email today to all users about an issue that was identified and fixed regarding authentication parameters. I thought I'd go into more technical detail here.

A bit of background:

When you sign in to your Standard Notes account, the app makes a network request to our servers to retrieve your "authentication parameters". This includes, amongst other things, the number of iterations by which to run your password through a repeat hashing function called PBKDF2.

PBKDF2 is a password based key derivation function. It takes a human inputted password, and hashes it several thousand times to "stretch" the password into something more secure. This way, any attacker who wanted to try to guess your password would need to run every single guess through a hashing function several thousand times, making it more difficult and time consuming to try a guess.

Because different platforms have different capabilities of how many hashing iterations they can handle, it's common to store the number of iterations, also known as the "cost", on the server side. This parameter is then retrieved when you attempt to sign in.

A problem arises when you begin to introduce "distrust" of the server. What if the server is under active attack, and replaces a valid iteration count of 100,000 with just 1? The client-side applications would receive the parameter of 1, run the user's password through PBKDF2 just one time, and send the hashed result back to the server. This hashed password is considerably weaker than what should have been sent: the user's password hashed 100,000 times.

This is a tricky problem. How do we keep a variable iteration count while also reducing the amount by which we trust the server? Companies like 1Password and LastPass both use PBKDF2 in the same way, and unfortunately do not protect against this vulnerability either. LastPass has a simple endpoint "lastpass.com/iterations.php" which is called when you attempt to login that returns a simple number: 5000 (may vary per account). This number is blindly trusted and login proceeds.

We decided to attempt to tackle this problem, since we aim for a higher level of distrust between the client and the server. This problem was first identified during our security audit, and the proposed solution by the auditors was to "authenticate" these parameters. This means that after registration, the user-facing app would take these parameters and "sign" them with a key derived from the user's password. The result of this is an "authentication tag" that is uploaded as part of the authentication parameters.

Now, when the app attempts to log in, it will retrieve the authentication parameters, including the iteration count and the authentication tag. It will ask the user for their password first, derive the necessary keys, and verify that the iteration count matches what was initially uploaded during registration. Great solution, right?

Not so fast. The issue is that since the authentication tag is publicly retrievable given an email address, and that the authentication tag is generated with a key derived from the user's password, an attacker could "download" this tag, and begin attempting to guess a user's password offline and comparing it against this value. For secure passwords, this isn't a problem in general as attempting to guess secure passwords is time-wise impossible. For common passwords, with a machine computing billions of guesses per minute, it becomes less impossible.

We immediately began working on a solution after we identified the problem. The first step was to update our applications to not rely on this method of verifying server parameters. Instead, we decided on a better solution: implementing client-side minimums. This means that if the server stored value for the iteration count was 3,000, and the server returned 1 instead, the application would deny login to this account.

As mentioned before, different platforms have different capabilities regarding the number of iterations they can handle. Web browsers that don't support WebCrypto can only handle about 3,000 iterations, while native platforms like Desktop, iOS, and Android can handle several hundred thousand without issue.

Here's the solution we've implemented and deployed:

  1. Implement a hard minimum iteration count of 3,000 on all platforms.

  2. Begin using an iteration count of 100,000 for new accounts. This means any new account created on web browsers that support WebCrypto (Google Chrome/Firefox), Desktop, iOS, and Android will use at least 100,000 iterations.

  3. Implement a backwards incompatible versioning system that allows us to increase the minimum allowable iteration count every year. Within the timeframe of 6-12 months, we will be raising this minimum to 100,000 on all platforms. This means that if you attempt to sign in and the server reports anything lower than 100,000 iterations, the account will be denied sign in by the application. This prevents the server from retrieving a weakened password hash.

(We're also looking into implementing WebCrypto on Safari).

That about sums it up. This is a tricky problem without an obvious solution, and in fact many companies don't protect against this at all. Client-side minimums appear to be a safe and effective solution to this problem. At the end of the day, our goal is to create a system where the only thing you ever have to trust is the application sitting right in front of you. This is no easy feat, but we're making great progress.

If you have any questions, please don't hesitate to reach out: mo@standardnotes.org.

jmason888 commented 7 years ago

Thank you for posting this. I was concerned about the authenticity of the email, and am not willing to install applications that were supplied in an email (the links don't even go to https://standardnotes.org/, instead they go to http://standardnotes.us14.list-manage.com/).

Please consider posting something about the update to your blog, making the updated desktop binaries available on your your homepage, and pushing the mobile updates to the relevant app stores, so that we can download them from known, trusted sources.

moughxyz commented 7 years ago

Hey James, good point. Definitely don't want to get users accustomed to installing applications from an email. I'll be sure to keep this in mind in the future.