How can prepared statements protect from SQL injection attacks?

前端 未结 9 2071
予麋鹿
予麋鹿 2020-11-21 05:40

How do prepared statements help us prevent SQL injection attacks?

Wikipedia says:

Prepared statements are resilient against SQL injection, because

9条回答
  •  Happy的楠姐
    2020-11-21 05:56

    Here is SQL for setting up an example:

    CREATE TABLE employee(name varchar, paymentType varchar, amount bigint);
    
    INSERT INTO employee VALUES('Aaron', 'salary', 100);
    INSERT INTO employee VALUES('Aaron', 'bonus', 50);
    INSERT INTO employee VALUES('Bob', 'salary', 50);
    INSERT INTO employee VALUES('Bob', 'bonus', 0);
    

    The Inject class is vulnerable to SQL injection. The query is dynamically pasted together with user input. The intent of the query was to show information about Bob. Either salary or bonus, based on user input. But the malicious user manipulates the input corrupting the query by tacking on the equivalent of an 'or true' to the where clause so that everything is returned, including the information about Aaron which was supposed to be hidden.

    import java.sql.*;
    
    public class Inject {
    
        public static void main(String[] args) throws SQLException {
    
            String url = "jdbc:postgresql://localhost/postgres?user=user&password=pwd";
            Connection conn = DriverManager.getConnection(url);
    
            Statement stmt = conn.createStatement();
            String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='" + args[0] + "'";
            System.out.println(sql);
            ResultSet rs = stmt.executeQuery(sql);
    
            while (rs.next()) {
                System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
            }
        }
    }
    

    Running this, the first case is with normal usage, and the second with the malicious injection:

    c:\temp>java Inject salary
    SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary'
    salary 50
    
    c:\temp>java Inject "salary' OR 'a'!='b"
    SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary' OR 'a'!='b'
    salary 100
    bonus 50
    salary 50
    bonus 0
    

    You should not build your SQL statements with string concatenation of user input. Not only is it vulnerable to injection, but it has caching implications on the server as well (the statement changes, so less likely to get a SQL statement cache hit whereas the bind example is always running the same statement).

    Here is an example of Binding to avoid this kind of injection:

    import java.sql.*;
    
    public class Bind {
    
        public static void main(String[] args) throws SQLException {
    
            String url = "jdbc:postgresql://localhost/postgres?user=postgres&password=postgres";
            Connection conn = DriverManager.getConnection(url);
    
            String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?";
            System.out.println(sql);
    
            PreparedStatement stmt = conn.prepareStatement(sql);
            stmt.setString(1, args[0]);
    
            ResultSet rs = stmt.executeQuery();
    
            while (rs.next()) {
                System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
            }
        }
    }
    

    Running this with the same input as the previous example shows the malicious code does not work because there is no paymentType matching that string:

    c:\temp>java Bind salary
    SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
    salary 50
    
    c:\temp>java Bind "salary' OR 'a'!='b"
    SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
    

提交回复
热议问题