Java secure coding guide: input injection

brief introduction

Injection is a very common problem in security. Today, let's discuss the prevention of SQL injection and XML injection in Java.

SQL injection

What is SQL injection?

SQL injection means that the user inputs some parameters, which eventually leads to the execution of SQL deviating from the original intention of the programmer, resulting in ultra vires or other types of errors.

In other words, the meaning of SQL has changed due to user input.

Take our most commonly used login SQL statements for example. We may write the following SQL statements:

@H_403_37@select * from user where username='<username>' and password='<password>'

We need the user to pass in username and password.

How to inject this SQL statement?

Very simply, when the user's username input is the following:

@H_403_37@somebody' or '1'='1

Then the whole SQL statement will become:

@H_403_37@select * from user where username='somebody' or '1'='1' and password='<password>'

If someone is a valid user, the language behind or will not be executed at all, resulting in the return of the user's information without verifying the password.

Similarly, a malicious attacker can enter the following content into password and get the same result:

@H_403_37@' or '1'='1

The entire SQL is parsed as:

@H_403_37@select * from user where username='somebody' and password='' or '1'='1'

This statement will return all user information, so that even if you don't know the user name, you can judge it through the SQL statement.

This is SQL injection.

SQL injection in Java

The most commonly used method in Java is to operate the database through JDBC. After we use JDBC to create a connection, we can execute SQL statements.

Let's take a look at an example of using JDBC SQL injection in Java.

First create a universal JDBC connection:

    public Connection getConnection() throws ClassNotFoundException,sqlException {
        Connection con = null;
            Class.forName("com.MysqL.jdbc.Driver");
            System.out.println("数据库驱动加载成功");
            con = DriverManager.getConnection("jdbc:MysqL://127.0.0.1:3306/MysqL?characterEncoding=UTF-8","root","");
            System.out.println("数据库连接成功");
          return con;
    }

Then assemble the SQL statement by yourself and then call:

public void jdbcWithInjection(String username,char[] password) throws sqlException,ClassNotFoundException {
        Connection connection = getConnection();
        if (connection == null) {
            // Handle error
        }
        try {
            String pwd = encodePassword(password);

            String sqlString = "SELECT * FROM user WHERE username = '"
                    + username +
                    "' AND password = '" + pwd + "'";
            Statement stmt = connection.createStatement();
            ResultSet rs = stmt.executeQuery(sqlString);

            if (!rs.next()) {
                throw new SecurityException(
                        "User name or password incorrect"
                );
            }
        } finally {
            try {
                connection.close();
            } catch (sqlException x) {
            }
        }
    }

In the above example, only username will be injected, but password will not, because we used the encodepassword method to convert password:

public String encodePassword(char[] password){
        return Base64.getEncoder().encodeToString(new String(password).getBytes());
    }

To prevent SQL injection, we generally recommend using Preparedstatement, Java sql. Preparedstatement can escape input parameters to prevent SQL injection.

Here is an example of incorrect use:

String sqlString = "SELECT * FROM user WHERE username = '"
                    + username +
                    "' AND password = '" + pwd + "'";
            PreparedStatement stmt = connection.prepareStatement(sqlString);
            ResultSet rs = stmt.executeQuery();

In the above code, we still assembled the SQL ourselves. Although we used the Preparedstatement in the end, it didn't achieve the effect.

Examples of correct use are as follows:

String sqlString =
                    "select * from user where username=? and password=?";
            PreparedStatement stmt = connection.prepareStatement(sqlString);
            stmt.setString(1,username);
            stmt.setString(2,pwd);
            ResultSet rs = stmt.executeQuery();

We need to set the user input into the Preparedstatement as a parameter, so as to escape.

SQL injection in XML

Extensible markup language (XML) is designed to help store, structure and transmit data. Due to its platform independence, flexibility and relative simplicity, XML has been used in many applications. However, due to its versatility, XML is vulnerable to various attacks, including XML injection.

So what is XML injection? Let's take an example:

<item>
  <name>Iphone20</name>
  <price>5000.0</price>
  <quantity>1</quantity>
</item>

In the above example, we used XML to define the price and quantity of an iPhone 20. An iPhone costs $20, 5000.

In the above XML, if quantity is the data entered by the user, the user can enter it as follows:

1</quantity><price>20.0</price><quantity>1

The resulting XML file is as follows:

<item>
  <name>Iphone20</name>
  <price>5000.0</price>
  <quantity>1</quantity>
  <price>20.0</price><quantity>1</quantity>
</item>

Generally speaking, if we find duplicate tags in the process of parsing XML, the following tags will overwrite the previous tags.

The result is that the current price of an iPhone 20 is 20 yuan, which is very cost-effective.

XML injected java code

Let's see how XML injection is implemented in Java code:

    public String createXMLInjection(String quantity){
        String xmlString = "<item>\n<name>Iphone20</name>\n"
                + "<price>5000.0</price>\n" + "<quantity>" + quantity
                + "</quantity></item>";
        return xmlString;
    }

You can see that we directly use the quantity entered by the user as the splicing of XML, which is obviously problematic.

How to solve it? There are two ways.

The first method is to verify the quantity entered by the user:

    public String createXML(String quantity){
        int count = Integer.parseUnsignedInt(quantity);
        String xmlString = "<item>\n<name>Iphone20</name>\n"
                + "<price>5000.0</price>\n" + "<quantity>" + count
                + "</quantity></item>";
        return xmlString;
    }

In the above code, we convert the quantity to integer, so as to avoid illegal input by the user.

The second method is to use XML schema to verify the format of the generated XML.

Let's take a look at how we define this XML Schema:


<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="item">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="price" type="xs:decimal"/>
      <xs:element name="quantity" type="xs:nonNegativeInteger"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>
</xs:schema>

Above, we defined a sequence of XML elements. If the user enters other XML in a non-defined format, an error will be reported.

Let's see how to write the corresponding java code:

StreamSource ss = new StreamSource(new File("schema.xsd"));
            Schema schema = sf.newSchema(ss);
            SAXParserFactory spf = SAXParserFactory.newInstance();
            spf.setSchema(schema);
            SAXParser saxParser = spf.newSAXParser();
            XMLReader reader = saxParser.getXMLReader();
            reader.setContentHandler(defHandler);
            reader.parse(xmlStream);

We listed the XML validation code above. For the complete code, please refer to the code link at the end of the article, which will not be posted one by one here.

Code for this article:

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

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>