mirror of
https://github.com/github/codeql.git
synced 2026-05-14 19:29:28 +02:00
Java: treat hash/encrypt/digest methods as sensitive-log sanitizers
The sensitive-log query (CWE-532) lacked sanitizers for hashed or encrypted data, while the sibling cleartext-storage query (CWE-312) already recognized methods with "encrypt", "hash", or "digest" in their names as sanitizers (CleartextStorageQuery.qll:86). This adds an EncryptionBarrier to SensitiveLoggingQuery that applies the same name-based heuristic, making the two queries consistent. Calls like DigestUtils.sha256Hex(password) or hashPassword(secret) are no longer flagged when their results are logged.
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `java/sensitive-log` query now treats method calls whose names contain "encrypt", "hash", or "digest" as sanitizers, consistent with the existing treatment in `java/cleartext-storage-in-log`. This reduces false positives when sensitive data is hashed or encrypted before logging.
|
||||
@@ -120,6 +120,19 @@ private class DefaultSensitiveLoggerBarrier extends SensitiveLoggerBarrier {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A barrier for sensitive data that has been hashed, encrypted, or digested before logging.
|
||||
* This is consistent with the treatment of encryption in `CleartextStorageQuery.qll` (CWE-312).
|
||||
*/
|
||||
private class EncryptionBarrier extends SensitiveLoggerBarrier {
|
||||
EncryptionBarrier() {
|
||||
exists(MethodCall mc |
|
||||
this.asExpr() = mc and
|
||||
mc.getMethod().getName().toLowerCase().matches(["%encrypt%", "%hash%", "%digest%"])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
|
||||
module SensitiveLoggerConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof SensitiveLoggerSource }
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
| Test.java:12:22:12:52 | ... + ... | Test.java:12:44:12:52 | authToken : String | Test.java:12:22:12:52 | ... + ... | This $@ is written to a log file. | Test.java:12:44:12:52 | authToken | potentially sensitive information |
|
||||
| Test.java:21:22:21:75 | ... + ... | Test.java:21:44:21:52 | authToken : String | Test.java:21:22:21:75 | ... + ... | This $@ is written to a log file. | Test.java:21:44:21:52 | authToken | potentially sensitive information |
|
||||
| Test.java:22:22:22:75 | ... + ... | Test.java:22:44:22:52 | authToken : String | Test.java:22:22:22:75 | ... + ... | This $@ is written to a log file. | Test.java:22:44:22:52 | authToken | potentially sensitive information |
|
||||
| Test.java:31:21:31:37 | ... + ... | Test.java:31:30:31:37 | password : String | Test.java:31:21:31:37 | ... + ... | This $@ is written to a log file. | Test.java:31:30:31:37 | password | potentially sensitive information |
|
||||
edges
|
||||
| Test.java:11:46:11:53 | password : String | Test.java:11:21:11:53 | ... + ... | provenance | Sink:MaD:2 |
|
||||
| Test.java:12:44:12:52 | authToken : String | Test.java:12:22:12:52 | ... + ... | provenance | Sink:MaD:1 |
|
||||
@@ -10,6 +11,7 @@ edges
|
||||
| Test.java:21:44:21:67 | substring(...) : String | Test.java:21:22:21:75 | ... + ... | provenance | Sink:MaD:1 |
|
||||
| Test.java:22:44:22:52 | authToken : String | Test.java:22:44:22:67 | substring(...) : String | provenance | MaD:3 |
|
||||
| Test.java:22:44:22:67 | substring(...) : String | Test.java:22:22:22:75 | ... + ... | provenance | Sink:MaD:1 |
|
||||
| Test.java:31:30:31:37 | password : String | Test.java:31:21:31:37 | ... + ... | provenance | Sink:MaD:2 |
|
||||
models
|
||||
| 1 | Sink: org.apache.logging.log4j; Logger; true; error; (String); ; Argument[0]; log-injection; manual |
|
||||
| 2 | Sink: org.apache.logging.log4j; Logger; true; info; (String); ; Argument[0]; log-injection; manual |
|
||||
@@ -25,4 +27,6 @@ nodes
|
||||
| Test.java:22:22:22:75 | ... + ... | semmle.label | ... + ... |
|
||||
| Test.java:22:44:22:52 | authToken : String | semmle.label | authToken : String |
|
||||
| Test.java:22:44:22:67 | substring(...) : String | semmle.label | substring(...) : String |
|
||||
| Test.java:31:21:31:37 | ... + ... | semmle.label | ... + ... |
|
||||
| Test.java:31:30:31:37 | password : String | semmle.label | password : String |
|
||||
subpaths
|
||||
|
||||
@@ -21,4 +21,17 @@ class Test {
|
||||
logger.error("Auth failed for: " + authToken.substring(1,5) + "..."); // $ Alert
|
||||
logger.error("Auth failed for: " + authToken.substring(0,8) + "..."); // $ Alert
|
||||
}
|
||||
|
||||
// Tests for hash/encryption sanitizer
|
||||
void testHashSanitizer(String password, String authToken) {
|
||||
Logger logger = null;
|
||||
logger.info("hash: " + hashPassword(password)); // Safe - hashed
|
||||
logger.info("hash: " + sha256Digest(authToken)); // Safe - digested
|
||||
logger.info("enc: " + encryptValue(password)); // Safe - encrypted
|
||||
logger.info("pw: " + password); // $ Alert - not hashed
|
||||
}
|
||||
|
||||
static String hashPassword(String input) { return input; }
|
||||
static String sha256Digest(String input) { return input; }
|
||||
static String encryptValue(String input) { return input; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user