mirror of
https://github.com/LukeMathWalker/zero-to-production.git
synced 2024-12-18 05:56:35 +00:00
Prevent user enumeration via timing attacks.
This commit is contained in:
parent
5492da0b38
commit
80a286113a
2 changed files with 25 additions and 10 deletions
|
@ -110,10 +110,20 @@ async fn validate_credentials(
|
|||
credentials: Credentials,
|
||||
pool: &PgPool,
|
||||
) -> Result<uuid::Uuid, PublishError> {
|
||||
let (user_id, expected_password_hash) = get_stored_credentials(&credentials.username, &pool)
|
||||
.await
|
||||
.map_err(PublishError::UnexpectedError)?
|
||||
.ok_or_else(|| PublishError::AuthError(anyhow::anyhow!("Unknown username.")))?;
|
||||
let mut user_id = None;
|
||||
let mut expected_password_hash = "$argon2id$v=19$m=15000,t=2,p=1$\
|
||||
gZiV/M1gPc22ElAH/Jh1Hw$\
|
||||
CWOrkoo7oJBQ/iyh7uJ0LO2aLEfrHwTWllSAxT0zRno"
|
||||
.to_string();
|
||||
|
||||
if let Some((stored_user_id, stored_password_hash)) =
|
||||
get_stored_credentials(&credentials.username, &pool)
|
||||
.await
|
||||
.map_err(PublishError::UnexpectedError)?
|
||||
{
|
||||
user_id = Some(stored_user_id);
|
||||
expected_password_hash = stored_password_hash;
|
||||
}
|
||||
|
||||
spawn_blocking_with_tracing(move || {
|
||||
verify_password_hash(expected_password_hash, credentials.password)
|
||||
|
@ -122,7 +132,7 @@ async fn validate_credentials(
|
|||
.context("Failed to spawn blocking task.")
|
||||
.map_err(PublishError::UnexpectedError)??;
|
||||
|
||||
Ok(user_id)
|
||||
user_id.ok_or_else(|| PublishError::AuthError(anyhow::anyhow!("Unknown username.")))
|
||||
}
|
||||
|
||||
#[tracing::instrument(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use argon2::password_hash::SaltString;
|
||||
use argon2::{Argon2, PasswordHasher};
|
||||
use argon2::{Algorithm, Argon2, Params, PasswordHasher, Version};
|
||||
use once_cell::sync::Lazy;
|
||||
use sqlx::{Connection, Executor, PgConnection, PgPool};
|
||||
use uuid::Uuid;
|
||||
|
@ -163,10 +163,15 @@ impl TestUser {
|
|||
|
||||
async fn store(&self, pool: &PgPool) {
|
||||
let salt = SaltString::generate(&mut rand::thread_rng());
|
||||
let password_hash = Argon2::default()
|
||||
.hash_password(self.password.as_bytes(), &salt)
|
||||
.unwrap()
|
||||
.to_string();
|
||||
// Match production parameters
|
||||
let password_hash = Argon2::new(
|
||||
Algorithm::Argon2id,
|
||||
Version::V0x13,
|
||||
Params::new(15000, 2, 1, None).unwrap(),
|
||||
)
|
||||
.hash_password(self.password.as_bytes(), &salt)
|
||||
.unwrap()
|
||||
.to_string();
|
||||
sqlx::query!(
|
||||
"INSERT INTO users (user_id, username, password_hash)
|
||||
VALUES ($1, $2, $3)",
|
||||
|
|
Loading…
Reference in a new issue