Rust: Add hash function sinks.

This commit is contained in:
Geoffrey White
2025-01-06 17:26:08 +00:00
parent d72b978bc7
commit ae0f4f10de
5 changed files with 99 additions and 15 deletions

View File

@@ -3,6 +3,6 @@
*/
private import codeql.rust.frameworks.Reqwest
private import codeql.rust.frameworks.RustCrypto
private import codeql.rust.frameworks.rustcrypto.RustCrypto
private import codeql.rust.frameworks.stdlib.Env
private import codeql.rust.frameworks.Sqlx

View File

@@ -5,6 +5,9 @@
private import rust
private import codeql.rust.Concepts
private import codeql.rust.dataflow.DataFlow
private import codeql.rust.dataflow.FlowSource
private import codeql.rust.dataflow.FlowSink
private import codeql.rust.dataflow.internal.DataFlowImpl
bindingset[algorithmName]
private string simplifyAlgorithmName(string algorithmName) {
@@ -55,3 +58,28 @@ class StreamCipherInit extends Cryptography::CryptographicOperation::Range {
override Cryptography::BlockMode getBlockMode() { result = "" }
}
/**
* An externally modelled operation that hashes data, for example a call to `md5::Md5::digest(data)`.
*/
class ModelledHashOperation extends Cryptography::CryptographicOperation::Range {
DataFlow::Node input;
CallExpr call;
string algorithmName;
ModelledHashOperation() {
sinkNode(input, "hasher-input") and
call = input.(Node::FlowSummaryNode).getSinkElement().getCall() and
call = this.asExpr().getExpr() and
algorithmName =
call.getFunction().(PathExpr).getPath().getQualifier().getPart().getNameRef().getText()
}
override DataFlow::Node getInitialization() { result = this }
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithmName) }
override DataFlow::Node getAnInput() { result = input }
override Cryptography::BlockMode getBlockMode() { none() } // (does not apply for hashing)
}

View File

@@ -0,0 +1,9 @@
extensions:
- addsTo:
pack: codeql/rust-all
extensible: sinkModel
data:
- ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::new_with_prefix", "Argument[0]", "hasher-input", "manual"]
- ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::update", "Argument[0]", "hasher-input", "manual"]
- ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::chain_update", "Argument[0]", "hasher-input", "manual"]
- ["repo:https://github.com/RustCrypto/traits:digest", "<_ as crate::digest::Digest>::digest", "Argument[0]", "hasher-input", "manual"]

View File

@@ -1,4 +1,51 @@
edges
nodes
subpaths
#select
| test.rs:14:9:14:24 | ...::digest | test.rs:14:26:14:39 | credit_card_no | test.rs:14:9:14:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure. | test.rs:14:26:14:39 | credit_card_no | Sensitive data (private) |
| test.rs:15:9:15:24 | ...::digest | test.rs:15:26:15:33 | password | test.rs:15:9:15:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:15:26:15:33 | password | Sensitive data (password) |
| test.rs:26:9:26:26 | ...::digest | test.rs:26:28:26:41 | credit_card_no | test.rs:26:9:26:26 | ...::digest | $@ is used in a hashing algorithm (SHA1) that is insecure. | test.rs:26:28:26:41 | credit_card_no | Sensitive data (private) |
| test.rs:27:9:27:26 | ...::digest | test.rs:27:28:27:35 | password | test.rs:27:9:27:26 | ...::digest | $@ is used in a hashing algorithm (SHA1) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:27:28:27:35 | password | Sensitive data (password) |
| test.rs:32:9:32:34 | ...::digest | test.rs:32:36:32:49 | credit_card_no | test.rs:32:9:32:34 | ...::digest | $@ is used in a hashing algorithm (SHA1) that is insecure. | test.rs:32:36:32:49 | credit_card_no | Sensitive data (private) |
| test.rs:33:9:33:34 | ...::digest | test.rs:33:36:33:43 | password | test.rs:33:9:33:34 | ...::digest | $@ is used in a hashing algorithm (SHA1) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:33:36:33:43 | password | Sensitive data (password) |
| test.rs:39:9:39:30 | ...::digest | test.rs:39:32:39:39 | password | test.rs:39:9:39:30 | ...::digest | $@ is used in a hashing algorithm (SHA3256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:39:32:39:39 | password | Sensitive data (password) |
| test.rs:60:9:60:24 | ...::digest | test.rs:60:26:60:37 | password_str | test.rs:60:9:60:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:60:26:60:37 | password_str | Sensitive data (password) |
| test.rs:62:9:62:24 | ...::digest | test.rs:62:26:62:37 | password_arr | test.rs:62:9:62:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:62:26:62:37 | password_arr | Sensitive data (password) |
| test.rs:64:9:64:24 | ...::digest | test.rs:64:26:64:37 | password_vec | test.rs:64:9:64:24 | ...::digest | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:64:26:64:37 | password_vec | Sensitive data (password) |
| test.rs:77:9:77:33 | ...::new_with_prefix | test.rs:77:35:77:42 | password | test.rs:77:9:77:33 | ...::new_with_prefix | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:77:35:77:42 | password | Sensitive data (password) |
edges
| test.rs:14:26:14:39 | credit_card_no | test.rs:14:9:14:24 | ...::digest | provenance | MaD:1 |
| test.rs:15:26:15:33 | password | test.rs:15:9:15:24 | ...::digest | provenance | MaD:1 |
| test.rs:26:28:26:41 | credit_card_no | test.rs:26:9:26:26 | ...::digest | provenance | MaD:1 |
| test.rs:27:28:27:35 | password | test.rs:27:9:27:26 | ...::digest | provenance | MaD:1 |
| test.rs:32:36:32:49 | credit_card_no | test.rs:32:9:32:34 | ...::digest | provenance | MaD:1 |
| test.rs:33:36:33:43 | password | test.rs:33:9:33:34 | ...::digest | provenance | MaD:1 |
| test.rs:39:32:39:39 | password | test.rs:39:9:39:30 | ...::digest | provenance | MaD:1 |
| test.rs:60:26:60:37 | password_str | test.rs:60:9:60:24 | ...::digest | provenance | MaD:1 |
| test.rs:62:26:62:37 | password_arr | test.rs:62:9:62:24 | ...::digest | provenance | MaD:1 |
| test.rs:64:26:64:37 | password_vec | test.rs:64:9:64:24 | ...::digest | provenance | MaD:1 |
| test.rs:77:35:77:42 | password | test.rs:77:9:77:33 | ...::new_with_prefix | provenance | MaD:2 |
models
| 1 | Sink: repo:https://github.com/RustCrypto/traits:digest; <_ as crate::digest::Digest>::digest; hasher-input; Argument[0] |
| 2 | Sink: repo:https://github.com/RustCrypto/traits:digest; <_ as crate::digest::Digest>::new_with_prefix; hasher-input; Argument[0] |
nodes
| test.rs:14:9:14:24 | ...::digest | semmle.label | ...::digest |
| test.rs:14:26:14:39 | credit_card_no | semmle.label | credit_card_no |
| test.rs:15:9:15:24 | ...::digest | semmle.label | ...::digest |
| test.rs:15:26:15:33 | password | semmle.label | password |
| test.rs:26:9:26:26 | ...::digest | semmle.label | ...::digest |
| test.rs:26:28:26:41 | credit_card_no | semmle.label | credit_card_no |
| test.rs:27:9:27:26 | ...::digest | semmle.label | ...::digest |
| test.rs:27:28:27:35 | password | semmle.label | password |
| test.rs:32:9:32:34 | ...::digest | semmle.label | ...::digest |
| test.rs:32:36:32:49 | credit_card_no | semmle.label | credit_card_no |
| test.rs:33:9:33:34 | ...::digest | semmle.label | ...::digest |
| test.rs:33:36:33:43 | password | semmle.label | password |
| test.rs:39:9:39:30 | ...::digest | semmle.label | ...::digest |
| test.rs:39:32:39:39 | password | semmle.label | password |
| test.rs:60:9:60:24 | ...::digest | semmle.label | ...::digest |
| test.rs:60:26:60:37 | password_str | semmle.label | password_str |
| test.rs:62:9:62:24 | ...::digest | semmle.label | ...::digest |
| test.rs:62:26:62:37 | password_arr | semmle.label | password_arr |
| test.rs:64:9:64:24 | ...::digest | semmle.label | ...::digest |
| test.rs:64:26:64:37 | password_vec | semmle.label | password_vec |
| test.rs:77:9:77:33 | ...::new_with_prefix | semmle.label | ...::new_with_prefix |
| test.rs:77:35:77:42 | password | semmle.label | password |
subpaths

View File

@@ -11,8 +11,8 @@ fn test_hash_algorithms(
// MD5
_ = md5::Md5::digest(harmless);
_ = md5::Md5::digest(credit_card_no); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(credit_card_no); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(password); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(encrypted_password);
// MD5 (alternative / older library)
@@ -23,20 +23,20 @@ fn test_hash_algorithms(
// SHA-1
_ = sha1::Sha1::digest(harmless);
_ = sha1::Sha1::digest(credit_card_no); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = sha1::Sha1::digest(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = sha1::Sha1::digest(credit_card_no); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = sha1::Sha1::digest(password); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = sha1::Sha1::digest(encrypted_password);
// SHA-1 checked
_ = sha1_checked::Sha1::digest(harmless);
_ = sha1_checked::Sha1::digest(credit_card_no); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = sha1_checked::Sha1::digest(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = sha1_checked::Sha1::digest(credit_card_no); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = sha1_checked::Sha1::digest(password); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = sha1_checked::Sha1::digest(encrypted_password);
// SHA-256 (appropriate for sensitive data hashing)
_ = sha3::Sha3_256::digest(harmless);
_ = sha3::Sha3_256::digest(credit_card_no);
_ = sha3::Sha3_256::digest(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = sha3::Sha3_256::digest(password); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = sha3::Sha3_256::digest(encrypted_password);
// Argon2 (appropriate for password hashing)
@@ -57,11 +57,11 @@ fn test_hash_code_patterns(
// hash different types of data
_ = md5::Md5::digest(harmless_str);
_ = md5::Md5::digest(password_str); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(password_str); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(harmless_arr);
_ = md5::Md5::digest(password_arr); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(password_arr); // $ Source Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(harmless_vec);
_ = md5::Md5::digest(password_vec); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::digest(password_vec); // $ Source Alert[rust/weak-sensitive-data-hashing]
// hash through a hasher object
let mut md5_hasher = md5::Md5::new();
@@ -74,7 +74,7 @@ fn test_hash_code_patterns(
_ = md5::Md5::new().chain_update(harmless).chain_update(password).chain_update(harmless).finalize(); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::new_with_prefix(harmless).finalize();
_ = md5::Md5::new_with_prefix(password).finalize(); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
_ = md5::Md5::new_with_prefix(password).finalize(); // $ Source Alert[rust/weak-sensitive-data-hashing]
// hash transformed data
_ = md5::Md5::digest(harmless.trim());