Java - This usage of java/lang/ProcessBuilder.<init>([Ljava/lang/String;)V can be vulnerable to Command Injection (Sonar)

araraujo :

how to avoid the "This usage of java/lang/ProcessBuilder.([Ljava/lang/String;)V can be vulnerable to Command Injection" sonar message for the code below ?

UPDATED

void assign(String path, File jarFile) {

   File cert = new File(path, "Cert");
   String password = "123";    

   File script = new File(path, "assign.bat");
   String command = "\"" + script.getAbsolutePath() + "\" " + password
                        + " \"" + cert.getAbsolutePath() + "\""
                        + " \"" + jarFile.getAbsolutePath()     + "\"";

   Process proc = new ProcessBuilder(command).start();

}
Steve :

It may be that you can reason in the current test code that there isn't actually a potential for abuse here, but I doubt that this is production code given a hard coded password of "123". Code like this tends to morph, and if you leave the potential for injection, you have to know too much about where all of the parameters are coming from to be able to rule out injection. If you do it the right way, you don't have to be so careful with the parameters.

Also, vulnerability scanners can't be this smart. Who knows what Sonar is looking for, but it is complaining about this particular variant of ProcessBuilder's constructor. Maybe it can recognize spaces in the input string and know there are parameters there. Who knows. Regardless, there's really no reason not to use the more robust version of the constructor. I expect doing so will avoid this message.

Just like with SQL, the answer is to pass the individual parameters to ProcessBuilder, like this:

void assign(String path, File jarFile) throws IOException {

    File cert = new File(path, "Cert");
    String password = "123";

    File script = new File(path, "assign.bat");
    String[] command = {
            script.getAbsolutePath(),
            password,
            cert.getAbsolutePath(),
            jarFile.getAbsolutePath()
    };

    Process proc = new ProcessBuilder(command).start();

}

This insures that the code knows the difference between the executable itself and the parameters, and so the executable can not be so easily manipulated. This also makes this particular code cleaner and easier to read.

Note that even in this case, to be sure this code is safe, you need to know intimately the behavior of File.getAbsolutePath() and/or exactly where 'path' and 'jarFile' are coming from. It's possible that File can be manipulated to return something bad from getAbsolutePath. I'm not saying it can, but the fact that I don't know either way is exactly why I'd want to use the multi-string variant of the ProcessBuilder constructor.

UPDATE: So Sonar is still complaining about this form. It turns out that this new version still uses the same constructor, because the constructor is a varargs constructor that can take "one or more" strings. I think the original solution I provided actually does solve the injection problem, but Sonar isn't able to recognize the fact that we've separated out the command arguments.

There's a ProcessBuilder constructor that takes a list instead of an array. This version of my example uses that constructor instead.

void assign(String path, File jarFile) throws IOException {

    File cert = new File(path, "Cert");
    String password = "123";

    File script = new File(path, "assign.bat");
    String[] command = {
            script.getAbsolutePath(),
            password,
            cert.getAbsolutePath(),
            jarFile.getAbsolutePath()
    };
    List<String> commandList = Arrays.asList(command);

    Process proc = new ProcessBuilder(commandList).start();
}

I hope this pleases Sonar. I'm guessing that this way of building a ProcessBuilder is what it's looking for.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=83725&siteId=1