Skip to content

Java: Promote Log Injection from experimental #7054

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

Merged
merged 12 commits into from
Jan 11, 2022
1 change: 1 addition & 0 deletions java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.JaxWS
private import semmle.code.java.frameworks.JoddJson
private import semmle.code.java.frameworks.JsonJava
private import semmle.code.java.frameworks.Logging
private import semmle.code.java.frameworks.Objects
private import semmle.code.java.frameworks.Optional
private import semmle.code.java.frameworks.Stream
Expand Down
329 changes: 329 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/Logging.qll

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions java/ql/lib/semmle/code/java/security/LogInjection.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/** Provides classes and predicates related to Log Injection vulnerabilities. */

import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow

/** A data flow sink for unvalidated user input that is used to log messages. */
abstract class LogInjectionSink extends DataFlow::Node { }

/**
* A node that sanitizes a message before logging to avoid log injection.
*/
abstract class LogInjectionSanitizer extends DataFlow::Node { }

/**
* A unit class for adding additional taint steps.
*
* Extend this class to add additional taint steps that should apply to the `LogInjectionConfiguration`.
*/
class LogInjectionAdditionalTaintStep extends Unit {
/**
* Holds if the step from `node1` to `node2` should be considered a taint
* step for the `LogInjectionConfiguration` configuration.
*/
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}

private class DefaultLogInjectionSink extends LogInjectionSink {
DefaultLogInjectionSink() { sinkNode(this, "logging") }
}

private class DefaultLogInjectionSanitizer extends LogInjectionSanitizer {
DefaultLogInjectionSanitizer() {
this.getType() instanceof BoxedType or this.getType() instanceof PrimitiveType
}
}
22 changes: 22 additions & 0 deletions java/ql/lib/semmle/code/java/security/LogInjectionQuery.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/** Provides taint tracking configurations to be used in queries related to the Log Injection vulnerability. */

import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.LogInjection

/**
* A taint-tracking configuration for tracking untrusted user input used in log entries.
*/
class LogInjectionConfiguration extends TaintTracking::Configuration {
LogInjectionConfiguration() { this = "LogInjectionConfiguration" }

override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

override predicate isSink(DataFlow::Node sink) { sink instanceof LogInjectionSink }

override predicate isSanitizer(DataFlow::Node node) { node instanceof LogInjectionSanitizer }

override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
any(LogInjectionAdditionalTaintStep c).step(node1, node2)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,15 @@ other forms of HTML injection.
</recommendation>

<example>
<p>In the example, a username, provided by the user, is logged using <code>logger.warn</code> (from <code>org.slf4j.Logger</code>).
<p>In the first example, a username, provided by the user, is logged using <code>logger.warn</code> (from <code>org.slf4j.Logger</code>).
In the first case (<code>/bad</code> endpoint), the username is logged without any sanitization.
If a malicious user provides <code>Guest'%0AUser:'Admin</code> as a username parameter,
the log entry will be split into two separate lines, where the first line will be <code>User:'Guest'</code> and the second one will be <code>User:'Admin'</code>.
</p>
<sample src="LogInjectionBad.java" />

<p> In the second case (<code>/good</code> endpoint), <code>matches()</code> is used to ensure the user input only has alphanumeric characters.
If a malicious user provides `Guest'%0AUser:'Admin` as a username parameter,
the log entry will not be split into two separate lines, resulting in a single line <code>User:'Guest'User:'Admin'</code>.</p>
<p> In the second example (<code>/good</code> endpoint), <code>matches()</code> is used to ensure the user input only has alphanumeric characters.
If a malicious user provides `Guest'%0AUser:'Admin` as a username parameter, the log entry will not be logged at all, preventing the injection.</p>

<sample src="LogInjectionGood.java" />
</example>
Expand Down
21 changes: 21 additions & 0 deletions java/ql/src/Security/CWE/CWE-117/LogInjection.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @name Log Injection
* @description Building log entries from user-controlled data may allow
* insertion of forged log entries by malicious users.
* @kind path-problem
* @problem.severity error
* @security-severity 7.8
* @precision medium
* @id java/log-injection
* @tags security
* external/cwe/cwe-117
*/

import java
import semmle.code.java.security.LogInjectionQuery
import DataFlow::PathGraph

from LogInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This $@ flows to a log entry.", source.getNode(),
"user-provided value"
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public class LogInjection {
public String good(@RequestParam(value = "username", defaultValue = "name") String username) {
// The regex check here, allows only alphanumeric characters to pass.
// Hence, does not result in log injection
if (username.matches("\w*")) {
if (username.matches("\\w*")) {
log.warn("User:'{}'", username);

return username;
}
}
Expand Down
4 changes: 4 additions & 0 deletions java/ql/src/change-notes/2021-11-04-log-injection-query.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: newQuery
---
* The query "Log Injection" (`java/log-injection`) has been promoted from experimental to the main query pack. Its results will now appear by default. The query was originally [submitted as an experimental query by @porcupineyhairs and @dellalibera](https://github.com/github/codeql/pull/5099).
38 changes: 0 additions & 38 deletions java/ql/src/experimental/Security/CWE/CWE-117/LogInjection.ql

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import java
import DataFlow
import semmle.code.java.frameworks.Networking
import semmle.code.java.security.QueryInjection
import experimental.semmle.code.java.Logging

/**
* A data flow source of the client ip obtained according to the remote endpoint identifier specified
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
*/

import java
import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.SensitiveActions
import experimental.semmle.code.java.Logging
import DataFlow
import PathGraph

Expand All @@ -36,9 +36,7 @@ class LoggerConfiguration extends DataFlow::Configuration {

override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }

override predicate isSink(DataFlow::Node sink) {
exists(LoggingCall c | sink.asExpr() = c.getALogArgument())
}
override predicate isSink(DataFlow::Node sink) { sinkNode(sink, "logging") }

override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
TaintTracking::localTaintStep(node1, node2)
Expand Down
40 changes: 0 additions & 40 deletions java/ql/src/experimental/semmle/code/java/Logging.qll

This file was deleted.

Loading