Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: made compliant code example

...

Code Block
bgColor#FFCCCC
/* Say this logfile contains:
 * CSV style: search string, time (unix), ip (integer)
 *
 * Alice,1267773881,2147651708
 * Bono,1267774881,2147651708
 * Charles,1267775881,1175563058
 * Cecilia,1267773222,291232332
 *
 * and the CSVLog class has a readLine() method which retrieves a single line from the CSVLog and returns null when at EOF
 */
private CSVLog logfile;
 
//an application repeatedly calls this function that searches through the search log for search suggestions for autocompletion
public Set<String> suggestSearches(String search)
{
   Set<String> searches = new HashSet<String>();
    
   //construct regex from user's string   //the regex matches valid lines and the grouping characters will limit the returned regex to the search string
   String regex = "^(" + search + ".*),[0-9]+?,[0-9]+?$";
   Pattern p = Pattern.compile(regex);
   String s;
   while ((s = logfile.readLine()) != null) { //gets a single line from the logfile
       Matcher m = p.matcher(s);
       if (m.find()) {
           String found = m.group(1);
           searches.add(found);
       }
   }
        
   return searches;
}

Compliant Solution

It is very difficult to filter out overly permissive regular expressions. It might be easier and more secure to rewrite the application to limit the usage of regular expressions.

For the above code sample, the easy solution is to parse Solutions include parsing the CSV into a class and limit the regular expression over the name field of the User classprior to matching or whitelisting only certain characters (such as letters and digits). Blacklisting might be difficult due to the variability of the regex language.

Code Block
bgColor#ccccff

import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.HashMap;

/\* Say Usagethis Test2logfile <regex>
&nbsp;\contains:
 * RegexCSV isstyle: usedsearch directlystring, without santization causing sensitive data to be exposed
&nbsp;\*
&nbsp;\* Imagine this program searches a database of users for usernames that match a regex
&nbsp;\* Non malicious usage: Test1 John.\*
&nbsp;\* Malicious usage: (?s)John.\*
&nbsp;*/
public class Test2
{
&nbsp;&nbsp; &nbsp;public static class User
&nbsp;&nbsp; &nbsp;{
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String name, password;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public User(String name, String password)
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;{
            setName(name);
            setPassword(password);
        }
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;private void setName(String n) { name = n; }
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;private void setPassword(String pw) { password = pw; }
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public String getName() { return name; }
&nbsp;&nbsp; &nbsp;}

&nbsp;&nbsp; &nbsp;public static void main(String\[\] args)
&nbsp;&nbsp; &nbsp;{
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (args.length < 1) {
            System.err.println("Failed to specify a regex");
            return;
        }

&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String sensitiveData; //represents sensitive data from a file or something
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int flags;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String regex;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Pattern p;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Matcher m;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;HashMap<String, User> userMap = new HashMap<String, User>();

&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;//imagine a CSV style database: user,password
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;sensitiveData = "JohnPaul,HearsGodsVoice\nJohnJackson,OlympicBobsleder\nJohnMayer,MakesBadMusic\n";
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String\[\] csvUsers = sensitiveData.split("\n");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (String csvUser : csvUsers) {
            String[] csvUserSplit = csvUser.split(",");
            String name = csvUserSplit[0];
            String pw = csvUserSplit[1];
            User u = new User(name, pw);
            userMap.put(name, u);
        }


&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;regex = args[0];
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;flags = 0;

&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.out.println("Pattern: \'" + regex + "\'");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;time (unix), ip (integer)
 *
 * Alice,1267773881,2147651708
 * Bono,1267774881,2147651708
 * Charles,1267775881,1175563058
 * Cecilia,1267773222,291232332
 *
 * and the CSVLog class has a readLine() method which retrieves a single line from the CSVLog and returns null when at EOF
 */
private CSVLog logfile;
 
//an application repeatedly calls this function that searches through the search log for search suggestions for autocompletion
public Set<String> suggestSearches(String search)
{
   Set<String> searches = new HashSet<String>();

   //filter search
   StringBuilder sb = new StringBuilder(search.length());
   for (int i = 0; i < search.length(); ++i) {
       char ch = search.charAt(i);
       if (Character.isLetterOrDigit(ch))
           sb.append(ch);
   }
   search = sb.toString();
    
   //construct regex from user's string   //the regex matches valid lines and the grouping characters will limit the returned regex to the search string
   String regex = "^(" + search + ".*),[0-9]+?,[0-9]+?$";
   Pattern p = Pattern.compile(regex, flags);


&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (String u : userMap.keySet()) {
            m    String s;
   while ((s = logfile.readLine()) != null) { //gets a single line from the logfile
       Matcher m = p.matcher(us);
                if  while (m.find()) {
                String          System.out.println("Found \'" + found = m.group(1) + "\'");;
           searches.add(found);
       }
      }
        }
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;System.err.println("DONE");
&nbsp;&nbsp; &nbsp;}
   return searches;
}

Risk Assessment

Rule

Severity

Liklihood

Remediation Cost

Priority

Level

IDS18-J

medium

probable

high

P8

L2

...