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

Rust: Weak hashing query #18471

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Rust: Weak hashing query #18471

wants to merge 15 commits into from

Conversation

geoffw0
Copy link
Contributor

@geoffw0 geoffw0 commented Jan 10, 2025

Add a weak hashing query for Rust (rust/weak-sensitive-data-hashing). We already had the necessary cryptography concepts, I recently added a sensitive data library, and @hvitved added the ability to express sources and sinks in MaD - which is everything needed for the query. Most of the new code is closely based on what we have in other languages, e.g. Ruby.

Naturally there are plans to add further models and data flow to catch more of the test cases in future, after the basic query has been merged.

Needs:

  • code review
  • docs review
  • DCA run

@geoffw0 geoffw0 added the Rust Pull requests that update Rust code label Jan 10, 2025
@Copilot Copilot bot review requested due to automatic review settings January 10, 2025 12:43
Copy link
Contributor

github-actions bot commented Jan 10, 2025

QHelp previews:

rust/ql/src/queries/security/CWE-328/WeakSensitiveDataHashing.qhelp

Use of a broken or weak cryptographic hashing algorithm on sensitive data

A broken or weak cryptographic hash function can leave data vulnerable, and should not be used in security related code.

A strong cryptographic hash function should be resistant to:

  • Pre-image attacks. If you know a hash value h(x), you should not be able to easily find the input x.
  • Collision attacks. If you know a hash value h(x), you should not be able to easily find a different input y with the same hash value h(x) = h(y).
  • Brute force. For passwords and other data with limited input space, if you know a hash value h(x) you should not be able to find the input x even using a brute force attack (without significant computational effort).
    As an example, both MD5 and SHA-1 are known to be vulnerable to collision attacks.

All of MD5, SHA-1, SHA-2 and SHA-3 are weak against offline brute forcing, so they are not suitable for hashing passwords. This includes SHA-224, SHA-256, SHA-384 and SHA-512, which are in the SHA-2 family.

Since it's OK to use a weak cryptographic hash function in a non-security context, this query only alerts when these are used to hash sensitive data (such as passwords, certificates, usernames).

Recommendation

Ensure that you use a strong, modern cryptographic hash function, such as:

  • Argon2, scrypt, bcrypt, or PBKDF2 for passwords and other data with limited input space where a dictionary-like attack is feasible.
  • SHA-2, or SHA-3 in other cases.
    Note that special purpose algorithms, which are used to ensure that a message comes from a particular sender, exist for message authentication. These algorithms should be used when appropriate, as they address common vulnerabilities of simple hashing schemes in this context.

Example

The following examples show hashing sensitive data using the MD5 hashing algorithm that is known to be vulnerable to collision attacks, and hashing passwords using the SHA-3 algorithm that is weak to brute force attacks:

// MD5 is not appropriate for hashing sensitive data.
let mut md5_hasher = md5::Md5::new();
...
md5_hasher.update(emergency_contact); // BAD
md5_hasher.update(credit_card_no); // BAD
...
my_hash = md5_hasher.finalize();

// SHA3-256 is not appropriate for hashing passwords.
my_hash = sha3::Sha3_256::digest(password); // BAD

To make these secure, we can use the SHA-3 algorithm for sensitive data and Argon2 for passwords:

// SHA3-256 *is* appropriate for hashing sensitive data.
let mut sha3_256_hasher = sha3::Sha3_256::new();
...
sha3_256_hasher.update(emergency_contact); // GOOD
sha3_256_hasher.update(credit_card_no); // GOOD
...
my_hash = sha3_256_hasher.finalize();

// Argon2 is appropriate for hashing passwords.
let argon2_salt = argon2::password_hash::Salt::from_b64(salt)?;
my_hash = argon2::Argon2::default().hash_password(password.as_bytes(), argon2_salt)?.to_string(); // GOOD

References

Copilot

This comment was marked as off-topic.

| file://:0:0:0:0 | [summary param] 0 in lang:alloc::_::crate::fmt::format | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::crate::fmt::format | MaD:9 |
| file://:0:0:0:0 | [summary param] self in lang:alloc::_::<crate::string::String>::as_str | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::<crate::string::String>::as_str | MaD:7 |
| file://:0:0:0:0 | [summary param] 0 in lang:alloc::_::crate::fmt::format | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::crate::fmt::format | MaD:14 |
| file://:0:0:0:0 | [summary param] self in lang:alloc::_::<crate::string::String>::as_str | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::<crate::string::String>::as_str | MaD:12 |
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hvitved this test is unrelated to the PR, apart from that they both use models-as-data. I think that means we shouldn't be outputting these IDs in the tests?

@geoffw0 geoffw0 added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Jan 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. Rust Pull requests that update Rust code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant