...
This regex will match any line in the log file, including the private ones.
Noncompliant Code Example
This noncompliant code example searches a log file using search terms from an untrusted user.
Code Block | ||
---|---|---|
| ||
import java.io.FileInputStream; import java.io.IOException; import java.nio.CharBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.util.regex.Matcher; import java.util.regex.Pattern; public class LogSearch { public static void FindLogEntry(String search) { // Construct regex dynamically from user string String regex = "(.*? +public\\[\\d+\\] +.*" + search + ".*)"; Pattern keywordPattern = Pattern.compile(regex); try (FileInputStream fis = new FileInputStream("log.txt")) { FileChannel channel = fis.getChannel(); // Get the file's size and map it into memory long size = channel.size(); final MappedByteBuffer mappedBuffer = channel.map( FileChannel.MapMode.READ_ONLY, 0, size); Charset charset = Charset.forName("ISO-8859-15"); final CharsetDecoder decoder = charset.newDecoder(); // Read file into char buffer CharBuffer log = decoder.decode(mappedBuffer); Matcher logMatcher = keywordPattern.matcher(log); while (logMatcher.find()) { String match = logMatcher.group(); if (match != null) { System.out.println(match); } } } catch (IOException ex) { System.err.println("thrown exception: " + ex.toString()); Throwable[] suppressed = ex.getSuppressed(); for (int i = 0; i < suppressed.length; i++) { System.err.println("suppressed exception: " + suppressed[i].toString()); } } return; } public static void main(String[] args) { FindLogEntry(args[0]); } } |
This code permits an attacker to perform a regex injection.
Noncompliant Code Example
This noncompliant code example periodically loads the log file into memory and allows clients to obtain keyword search suggestions by passing the keyword as an argument to suggestSearches()
.
Code Block | ||
---|---|---|
| ||
public class Keywords {
private static ScheduledExecutorService scheduler
= Executors.newSingleThreadScheduledExecutor();
private static CharBuffer log;
private static final Object lock = new Object();
// Map log file into memory, and periodically reload
static {
try {
FileChannel channel = new FileInputStream(
"path").getChannel();
// Get the file's size and map it into memory
int size = (int) channel.size();
final MappedByteBuffer mappedBuffer = channel.map(
FileChannel.MapMode.READ_ONLY, 0, size);
Charset charset = Charset.forName("ISO-8859-15");
final CharsetDecoder decoder = charset.newDecoder();
log = decoder.decode(mappedBuffer); // Read file into char buffer
Runnable periodicLogRead = new Runnable() {
@Override public void run() {
synchronized(lock) {
try {
log = decoder.decode(mappedBuffer);
} catch (CharacterCodingException e) {
// Forward to handler
}
}
}
};
scheduler.scheduleAtFixedRate(periodicLogRead,
0, 5, TimeUnit.SECONDS);
} catch (Throwable t) {
// Forward to handler
}
}
public static Set<String> suggestSearches(String search) {
synchronized(lock) {
Set<String> searches = new HashSet<String>();
// Construct regex dynamically from user string
String regex = "(.*? +public\\[\\d+\\] +.*" + search + ".*)";
Pattern keywordPattern = Pattern.compile(regex);
Matcher logMatcher = keywordPattern.matcher(log);
while (logMatcher.find()) {
String found = logMatcher.group();
searches.add(found);
}
return searches;
}
}
}
|
This code permits a trusted user to search for public log messages such as "error." However, it also allows a malicious attacker to perform the regex injection previously described.
Compliant Solution (Whitelisting)
...