Keats / rust-bcrypt

Easily hash and verify passwords using Bcrypt
MIT License
340 stars 49 forks source link

verify Function Incorrectly Validates Different Tokens Against the Same Hash #86

Closed hakouguelfen closed 2 months ago

hakouguelfen commented 2 months ago

Hi, I'm encountering an issue with the verify function where two different JWT tokens are both validating successfully against the same hashed value.

use bcrypt::{hash, verify, DEFAULT_COST};

fn main() {
    let token1 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2NmM5YTc2OWUwMDhmNmY4ZjRiOWZjZjUiLCJleHAiOjE3MjcwOTQ3NzgsImlhdCI6MTcyNTc5ODc3OCwidHlwIjoiUmVmcmVzaFRva2VuIiwicm9sZSI6IlVzZXIifQ.8IW-Q3KGJ3a_c6f8SJlyGPKyK_tbj4L5NjnhxcWGrGY";
    let token2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2NmM5YTc2OWUwMDhmNmY4ZjRiOWZjZjUiLCJleHAiOjE3MjcwOTQ3OTEsImlhdCI6MTcyNTc5ODc5MSwidHlwIjoiUmVmcmVzaFRva2VuIiwicm9sZSI6IlVzZXIifQ.0s8E4PE4zgODWoOB3SGZVPSL5GCNlJ4PK2BKtd3tW3g";

    let hashed = hash(&token1, DEFAULT_COST).unwrap();

    let valid1 = verify(&token1, &hashed).unwrap();
    let valid2 = verify(&token2, &hashed).unwrap();

    dbg!(valid1); // Expected: true
    dbg!(valid2); // Expected: false, but I got true
}
tarcieri commented 2 months ago

bcrypt has a maximum password length of 72 bytes (or 71 if you could a NUL terminator byte).

It seems rust-bcrypt silently truncates the input to 72 bytes if it exceeds this limit:

https://github.com/Keats/rust-bcrypt/blob/9c9e138/src/lib.rs#L117-L119

It seems like it should instead return an error in the event the input is longer than 72 bytes, rather than silently truncating.

hakouguelfen commented 2 months ago

thank you