# SQL注入

# 欣赏一段JDBC代码

    public static void main(String[] args) throws SQLException {
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql", "root", "123456");

        Statement statement = connection.createStatement();

        String username="root";

        String sql = "select * from user where User='"+username+"'";

        System.out.println(sql);

        ResultSet resultSet = statement.executeQuery(sql);

        while (resultSet.next()){
            System.out.println(resultSet.getString("host"));
        }

        resultSet.close();
        statement.close();
        connection.close();
    }

# 分析

这里的 String sql = "select * from user where User='"+username+"'"; 
存在sql的拼接,所以就存在SQL注入的风险,只要修改username的值就能任意操作SQL语句的执行。
例如将username赋值于 username="' or 1=1#",就能查询出所有的数据
(select * from user where User='' or 1=1#';)
如果是账号密码登录的话还能造成任意密码登录的安全漏洞。

# 解决方法

采用预编译的方式处理

# 1.JDBC代码

public static void main(String[] args) throws SQLException {
    Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql", "root", "123456");
    
    String sql = "select * from user where User=?";  //变量采用占位符处理
    PreparedStatement preparedStatement = connection.prepareStatement(sql); 
    preparedStatement.setString(1,"root"); //在位置处设置值
    
    ResultSet resultSet = preparedStatement.executeQuery();
    
    while (resultSet.next()){
        System.out.println(resultSet.getString("host"));
    }

    resultSet.close();
    preparedStatement.close();
    connection.close();
}

# 2.druid代码

public static void main(String[] args) throws Exception {
    Properties properties = new Properties();
    InputStream resourceAsStream = druidTest.class.getClassLoader().getResourceAsStream("db.properties");

    properties.load(resourceAsStream);
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

    Connection connection = dataSource.getConnection();

    PreparedStatement preparedStatement = connection.prepareStatement("select * from user where Host=?");

    preparedStatement.setString(1,"%");
    ResultSet resultSet = preparedStatement.executeQuery();


    while (resultSet.next()){
        String host = resultSet.getString("User");
        System.out.println(host);
    }

}

# 3.spring-jdbctemplate代码

public static void main(String[] args) throws SQLException {
    DruidDataSource druidDataSource = new DruidDataSource();
    druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/mysql");
    druidDataSource.setUsername("root");
    druidDataSource.setPassword("123456");


    JdbcTemplate jdbcTemplate = new JdbcTemplate(druidDataSource);
    List<user> query = jdbcTemplate.query("select User,Host from user where User=?", new BeanPropertyRowMapper<user>(user.class),"root");
    System.out.println(query);
    for (user user : query) {
        System.out.println(user.getHost());
    }
}

# 4.ESAPI

String id ="1 and 1=1 and '1'='1";
String query ="SELECT user_id FROM user_data WHERE id = " + ESAPI.encoder().encodeForSQL(new MySQLCodec(MySQLCodec.Mode.STANDARD),id);
//mysql -> new MySQLCodec(MySQLCodec.Mode.STANDARD)
//oracle -> new OracleCodec()

System.out.println(query);   // SELECT user_id FROM user_data WHERE id = 1 and 1\=1 and \'1\'\=\'1