...
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 keywordPatternsearchPattern = 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 = keywordPatternsearchPattern.matcher(log); while (logMatcher.find()) { String match = logMatcher.group(); if (match != null!match.isEmpty()) { 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.
Compliant Solution (Whitelisting)
This compliant solution filters sanitizes the search terms at the beginning of the FindLogEntry(),
filtering out nonalphanumeric characters (except space and single quote) from the search string, which prevents regex injection.
Code Block | ||
---|---|---|
| ||
public class Keywords { // ... public static Set<String>void suggestSearchesFindLogEntry(String search) { // Sanitize synchronized (lock) { Set<String> searches = new HashSet<String>(); search string StringBuilder sb = new StringBuilder(search.length()); for (int i = 0; i < search.length(); ++i) { char ch = search.charAt(i); if (Character.isLetterOrDigit(ch) || ch == ' ' || ch == '\'') { sb.append(ch); } } } } search = sb.toString(); // Construct regex dynamically from user string String regex =// "(.*? +public\\[\\d+\\] +.*" + search + ".*)"; // ... } } } |
This solution also limits the set of valid prevents regex injection but also restricts search terms. For instanceexample, a user may no longer search for "name =
" because the =
character would be sanitized out of the regexnonalphanumeric characters are removed from the search term.
Compliant Solution
Another method of mitigating this vulnerability is to filter out the sensitive information prior to matching. Such a solution would require the filtering to be done every time the log file is periodically refreshed, incurring extra complexity and a performance penalty. Sensitive information may still be exposed if the log format changes but the class is not also refactored to accommodate these changes.
...