Skip to content

Commit 5c9fb23

Browse files
authored
Merge pull request github#3090 from luchua-bc/java-insert-sensitive-info-into-log
Java: CWE-532 sensitive info logging
2 parents 396ccda + 7b88988 commit 5c9fb23

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
public static void main(String[] args) {
2+
{
3+
private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class);
4+
5+
String password = "Pass@0rd";
6+
7+
// BAD: user password is written to debug log
8+
logger.debug("User password is "+password);
9+
}
10+
11+
{
12+
private static final Logger logger = LogManager.getLogger(SensitiveInfoLog.class);
13+
14+
String password = "Pass@0rd";
15+
16+
// GOOD: user password is never written to debug log
17+
}
18+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>Information written to log files can be of a sensitive nature and give valuable guidance to an attacker or expose sensitive user information. Third-party logging utilities like Log4J and SLF4J are widely used in Java projects. When sensitive information is written to logs without properly set logging levels, it is accessible to potential attackers who can use it to gain access to
8+
file storage.</p>
9+
</overview>
10+
11+
<recommendation>
12+
<p>Do not write secrets into the log files and enforce proper logging level control.</p>
13+
</recommendation>
14+
15+
<example>
16+
<p>The following example shows two ways of logging sensitive information. In the 'BAD' case,
17+
the credentials are simply written to a debug log. In the 'GOOD' case, the credentials are never written to debug logs.</p>
18+
<sample src="SensitiveInfoLog.java" />
19+
</example>
20+
21+
<references>
22+
<li>
23+
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html">OWASP Logging Guide</a>
24+
</li>
25+
</references>
26+
</qhelp>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* @id java/sensitiveinfo-in-logfile
3+
* @name Insertion of sensitive information into log files
4+
* @description Writing sensitive information to log files can give valuable guidance to an attacker or expose sensitive user information.
5+
* @kind path-problem
6+
* @tags security
7+
* external/cwe-532
8+
*/
9+
10+
import java
11+
import semmle.code.java.dataflow.TaintTracking
12+
import DataFlow
13+
import PathGraph
14+
15+
/**
16+
* Gets a regular expression for matching names of variables that indicate the value being held is a credential
17+
*/
18+
private string getACredentialRegex() {
19+
result = "(?i).*pass(wd|word|code|phrase)(?!.*question).*" or
20+
result = "(?i)(.*username|url).*"
21+
}
22+
23+
/** Variable keeps sensitive information judging by its name * */
24+
class CredentialExpr extends Expr {
25+
CredentialExpr() {
26+
exists(Variable v | this = v.getAnAccess() | v.getName().regexpMatch(getACredentialRegex()))
27+
}
28+
}
29+
30+
/** Class of popular logging utilities * */
31+
class LoggerType extends RefType {
32+
LoggerType() {
33+
this.hasQualifiedName("org.apache.log4j", "Category") or //Log4J
34+
this.hasQualifiedName("org.slf4j", "Logger") //SLF4j and Gradle Logging
35+
}
36+
}
37+
38+
predicate isSensitiveLoggingSink(DataFlow::Node sink) {
39+
exists(MethodAccess ma |
40+
ma.getMethod().getDeclaringType() instanceof LoggerType and
41+
(ma.getMethod().hasName("debug") or ma.getMethod().hasName("trace")) and //Check low priority log levels which are more likely to be real issues to reduce false positives
42+
sink.asExpr() = ma.getAnArgument()
43+
)
44+
}
45+
46+
class LoggerConfiguration extends DataFlow::Configuration {
47+
LoggerConfiguration() { this = "Logger Configuration" }
48+
49+
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
50+
51+
override predicate isSink(DataFlow::Node sink) { isSensitiveLoggingSink(sink) }
52+
53+
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
54+
TaintTracking::localTaintStep(node1, node2)
55+
}
56+
}
57+
58+
from LoggerConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
59+
where cfg.hasFlowPath(source, sink)
60+
select sink.getNode(), source, sink, "Outputting $@ to log.", source.getNode(),
61+
"sensitive information"

0 commit comments

Comments
 (0)