Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate API tokens with a secure RNG, store hashed #2637

Merged
merged 3 commits into from Jul 14, 2020

Conversation

sgrif
Copy link
Contributor

@sgrif sgrif commented Jul 14, 2020

Note: The contents of this PR have already been deployed to production, as this was a security issue. The code in this PR is the minimum number of changes needed to rebase what was deployed today onto master. Unfortunately, since this was done in parallel with some refactoring to the errors module, this means some of the added code doesn't look like the rest of the code base. However, master currently does not reflect what is in production, so any cleanup should come as a followup PR. The purpose of this is mainly to get master in sync with prod after going through bors.

This addresses a security issue with the way crates.io generates API
tokens. Prior to this commit, they were generated using the PostgreSQL
random function, which is not a secure PRNG. Additionally, the tokens
were stored in plain text, which would give an attacker who managed to
compromise our database access to all user's API tokens. This commit
addresses both changes.

An advisory about the problem was posted at
https://blog.rust-lang.org/2020/07/14/crates-io-security-advisory.html

The tokens are now generated using the OS's random number generator,
which maps to C's getrandom function, which is secure and
unpredictable.

The tokens are hashed using sha256. The choice to use a fast hashing
function such as this one instead of one typically used for passwords
(such as bcrypt or argon2) was intentional. Unlike passwords, our API
tokens are known to be 32 characters and are truly random, giving us 192
bits of entropy. This means that even with a fast hashing function,
actually finding a token from that hash before the death of human
civilization is infeasible.

Additionally, unlike passwords, API tokens need to be checked on every
request where they're used, instead of once at sign in. This means that
a slower hashing function would put significantly more load on our
server than they would when used for passwords.

We opted to use sha256 instead of bcrypt with a lower cost due to the
mandatory salt in bcrypt. If we salt the values before hashing them, the
tokens can no longer directly be used to identify themselves, and we
would need to include another identifier in the token given to the user.
While this is feasible, it leads to a very obtuse looking token, and
more complex code.

r? @jtgeibel

This addresses a security issue with the way crates.io generates API
tokens. Prior to this commit, they were generated using the PostgreSQL
`random` function, which is not a secure PRNG. Additionally, the tokens
were stored in plain text, which would give an attacker who managed to
compromise our database access to all user's API tokens. This commit
addresses both changes.

An advisory about the problem was posted at
https://blog.rust-lang.org/2020/07/14/crates-io-security-advisory.html

The tokens are now generated using the OS's random number generator,
which maps to C's `getrandom` function, which is secure and
unpredictable.

The tokens are hashed using sha256. The choice to use a fast hashing
function such as this one instead of one typically used for passwords
(such as bcrypt or argon2) was intentional. Unlike passwords, our API
tokens are known to be 32 characters and are truly random, giving us 192
bits of entropy. This means that even with a fast hashing function,
actually finding a token from that hash before the death of human
civilization is infeasible.

Additionally, unlike passwords, API tokens need to be checked on every
request where they're used, instead of once at sign in. This means that
a slower hashing function would put significantly more load on our
server than they would when used for passwords.

We opted to use sha256 instead of bcrypt with a lower cost due to the
mandatory salt in bcrypt. If we salt the values before hashing them, the
tokens can no longer directly be used to identify themselves, and we
would need to include another identifier in the token given to the user.
While this is feasible, it leads to a very obtuse looking token, and
more complex code.
@sgrif sgrif force-pushed the sg-security-advisory-2020-07-14 branch from e8c2a27 to d0dd084 Compare July 14, 2020 19:34
@jtgeibel
Copy link
Member

This looks good to me, thanks for resolving merge conflicts and taming clippy! I compared this to our working repo and don't see anything unexpected.

@bors r+

@bors
Copy link
Contributor

bors commented Jul 14, 2020

📌 Commit 380be53 has been approved by jtgeibel

@bors
Copy link
Contributor

bors commented Jul 14, 2020

⌛ Testing commit 380be53 with merge 07d42e9...

@bors
Copy link
Contributor

bors commented Jul 14, 2020

☀️ Test successful - checks-travis
Approved by: jtgeibel
Pushing 07d42e9 to master...

@bors bors merged commit 07d42e9 into master Jul 14, 2020
@jtgeibel jtgeibel deleted the sg-security-advisory-2020-07-14 branch July 14, 2020 22:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants