mirror of
https://github.com/github/codeql.git
synced 2025-12-21 19:26:31 +01:00
Merge pull request #7054 from atorralba/atorralba/promote-log-injection
Java: Promote Log Injection from experimental
This commit is contained in:
48
java/ql/src/Security/CWE/CWE-117/LogInjection.qhelp
Normal file
48
java/ql/src/Security/CWE/CWE-117/LogInjection.qhelp
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
|
||||
<p>If unsanitized user input is written to a log entry, a malicious user may be able to forge new log entries.</p>
|
||||
|
||||
<p>Forgery can occur if a user provides some input creating the appearance of multiple
|
||||
log entries. This can include unescaped new-line characters, or HTML or other markup.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
User input should be suitably sanitized before it is logged.
|
||||
</p>
|
||||
<p>
|
||||
If the log entries are plain text then line breaks should be removed from user input, using for example
|
||||
<code>String replace(char oldChar, char newChar)</code> or similar. Care should also be taken that user input is clearly marked
|
||||
in log entries, and that a malicious user cannot cause confusion in other ways.
|
||||
</p>
|
||||
<p>
|
||||
For log entries that will be displayed in HTML, user input should be HTML encoded before being logged, to prevent forgery and
|
||||
other forms of HTML injection.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<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 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>
|
||||
|
||||
<references>
|
||||
<li>OWASP: <a href="https://owasp.org/www-community/attacks/Log_Injection">Log Injection</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
21
java/ql/src/Security/CWE/CWE-117/LogInjection.ql
Normal file
21
java/ql/src/Security/CWE/CWE-117/LogInjection.ql
Normal file
@@ -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"
|
||||
24
java/ql/src/Security/CWE/CWE-117/LogInjectionBad.java
Normal file
24
java/ql/src/Security/CWE/CWE-117/LogInjectionBad.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package com.example.restservice;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class LogInjection {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(LogInjection.class);
|
||||
|
||||
// /bad?username=Guest'%0AUser:'Admin
|
||||
@GetMapping("/bad")
|
||||
public String bad(@RequestParam(value = "username", defaultValue = "name") String username) {
|
||||
log.warn("User:'{}'", username);
|
||||
// The logging call above would result in multiple log entries as shown below:
|
||||
// User:'Guest'
|
||||
// User:'Admin'
|
||||
return username;
|
||||
}
|
||||
}
|
||||
|
||||
25
java/ql/src/Security/CWE/CWE-117/LogInjectionGood.java
Normal file
25
java/ql/src/Security/CWE/CWE-117/LogInjectionGood.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package com.example.restservice;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class LogInjection {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(LogInjection.class);
|
||||
|
||||
// /good?username=Guest'%0AUser:'Admin
|
||||
@GetMapping("/good")
|
||||
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*")) {
|
||||
log.warn("User:'{}'", username);
|
||||
|
||||
return username;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user