Java security coding guide: input verification

Introduction

In order to ensure the security of the java program, any input from external users is considered to have malicious intentions, and we need to verify all user input to a certain degree.

This article will lead you to explore some scenarios of user input verification. Let's take a look.

Verify after string standardization

Usually we need to filter some special characters when performing string verification, and then perform string verification after filtering.

We know that characters in java are encoded based on Unicode. But in Unicode, the same character may have different representations. So we need to standardize the characters.

There is a special class Normalizer in java to deal with the problem of character standardization.

Let's look at the following example:

    public void testNormalizer(){
    
    
        System.out.println(Normalizer.normalize("\u00C1", Normalizer.Form.NFKC));
        System.out.println(Normalizer.normalize("\u0041\u0301", Normalizer.Form.NFKC));
    }

Output result:

Á
Á

We can see that although the Unicode of the two are not the same, the final character represented is the same. So when we perform character verification, we must first normalize.

Consider the following example:

    public void falseNormalize(){
    
    
        String s = "\uFE64" + "script" + "\uFE65";
        Pattern pattern = Pattern.compile("[<>]"); // 检查是否有尖括号
        Matcher matcher = pattern.matcher(s);
        if (matcher.find()) {
    
    
            throw new IllegalStateException();
        }
        s = Normalizer.normalize(s, Normalizer.Form.NFKC);
    }

Among them, \uFE64 means <, and \uFE65 means >. The original intention of the program is to judge whether the input string contains angle brackets, but because the direct input is unicode characters, direct compile cannot be detected.

We need to make the following changes to the code:

    public void trueNormalize(){
    
    
        String s = "\uFE64" + "script" + "\uFE65";
        s = Normalizer.normalize(s, Normalizer.Form.NFKC);
        Pattern pattern = Pattern.compile("[<>]"); // 检查是否有尖括号
        Matcher matcher = pattern.matcher(s);
        if (matcher.find()) {
    
    
            throw new IllegalStateException();
        }
    }

Perform normalize operation first, and then perform character verification.

Pay attention to the formatting of untrusted strings

We often use formatting to format strings. If the formatted string contains user input information when formatting, then we must pay attention.

Look at the following example:

    public void wrongFormat(){
    
    
        Calendar c = new GregorianCalendar(2020, GregorianCalendar.JULY, 27);
        String input=" %1$tm";
        System.out.format(input + " 时间不匹配,应该是某个月的第 %1$terd 天", c);
    }

There is no problem at first glance, but our input contains formatting information, and the final output is:

 07 时间不匹配,应该是某个月的第 27rd 天

In a disguised form, we have obtained the internal information of the system. In some cases, the internal logic of the system may be exposed.

In the above example, we should also use input as a parameter, as shown below:

    public void rightFormat(){
    
    
        Calendar c = new GregorianCalendar(2020, GregorianCalendar.JULY, 27);
        String input=" %1$tm";
        System.out.format("%s 时间不匹配,应该是某个月的第 %terd 天",input, c);
    }

Output result:

 %1$tm 时间不匹配,应该是某个月的第 27rd 天

Use Runtime.exec() carefully

We know that Runtime.exec() is used to call system commands. If a malicious user calls "rm -rf /", everything is done.

Therefore, when we call Runtime.exec(), we must be careful to detect user input.

Consider the following example:

    public void wrongExec() throws IOException {
    
    
        String dir = System.getProperty("dir");
        Runtime rt = Runtime.getRuntime();
        Process proc = rt.exec(new String[] {
    
    "sh", "-c", "ls " + dir});
    }

In the above example, we read dir from the system properties, and then executed the system ls command to view the contents of dir.

If a malicious user assigns dir to:

/usr & rm -rf /

Then the command actually executed by the system is:

sh -c 'ls /usr & rm -rf /'

This leads to malicious deletion.

There are several ways to solve the above problems. The first way is to check the input. For example, we only run dir to contain specific characters:

    public void correctExec1() throws IOException {
    
    
        String dir = System.getProperty("dir");
        if (!Pattern.matches("[0-9A-Za-z@.]+", dir)) {
    
    
            // Handle error
        }
        Runtime rt = Runtime.getRuntime();
        Process proc = rt.exec(new String[] {
    
    "sh", "-c", "ls " + dir});
    }

The second method is to use the switch statement to limit specific input:

    public void correctExec2(){
    
    
        String dir = System.getProperty("dir");
        switch (dir){
    
    
            case "/usr":
                System.out.println("/usr");
                break;
            case "/local":
                System.out.println("/local");
                break;
            default:
                break;
        }
    }

Another is not to use Runtime.exec () method, but to use the method that comes with java.

Regular expression matching

In the regular expression construction process, if user-defined input is used, input verification is also required.

Consider the following regular expression:

(.*? +public\[\d+\] +.*<SEARCHTEXT>.*)

The above expression is intended to search for user input in log information such as public[1234].

But the user can actually enter the following information:

.*)|(.*

Eventually the regular expression becomes the following:

(.*? +public\[\d+\] +.*.*)|(.*.*)

This results in matching all log information.

There are also two solutions. One is to use a whitelist to determine user input. One is to use Pattern.quote() to escape malicious characters.

The code of this article:

learn-java-base-9-to-20/tree/master/security

This article has been included in http://www.flydean.com/java-security-code-line-input/

The most popular interpretation, the most profound dry goods, the most concise tutorial, and many tips you don't know are waiting for you to discover!

Welcome to pay attention to my official account: "programs those things", know technology, know you better!

Guess you like

Origin blog.csdn.net/superfjj/article/details/108704062