SQL注入漏洞通过preparedStatement

时间:2014-07-29 20:59:12

标签: java sql jdbc

像这样的声明

String query = "SELECT * FROM users WHERE userid ='"+ userid + "'" + " AND password='" + password + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);

符合SQL注入条件。但 PreparedStatement如何帮助防止SQL注入?请考虑以下情形:

PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users WHERE userid=? AND password=?");
stmt.setString(1, userid);
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery();

如果有人输入userId = "abc"password = "1=1"会怎么样,因为这也会被视为有效的字符串......

4 个答案:

答案 0 :(得分:6)

这可以保护您的确切方式取决于数据库,但有两个明显的选择:

  • 数据库驱动程序可以执行字符串插值并生成SQL语句,以确保正确转义所有参数。
  • 数据库驱动程序可以完全按照您指定的方式传递SQL到数据库,并通过完全独立的通道传递参数的值,这不需要任何转义,因为它只是包含值。

在我看来,后者是一个更明智的解决方案,因为它允许数据库真正简单地缓存查询计划,认识到两个查询除参数值之外完全相同。我希望任何现代数据库都能在其原生通信协议中支持这一点。

答案 1 :(得分:3)

    String query = "SELECT * FROM users WHERE userid ='"+ userid + "'" + " AND password='" + password + "'";

这里,如果您正在尝试演示sql注入,则为password的值 可能是这样的:'或1 = 1 OR''='

然后,发送到DB服务器执行的结果SQL是 -

SELECT * FROM users WHERE userid ='abc' AND password='' OR 1=1 OR ''=''

因此,无论用户名和密码如何,它都会从表中选择所有条目,因为 userid ='abc'AND password =''OR 1 = 1 OR''='' 总是如此。任何未经授权的人都可以访问所有用户的数据。

对于使用参数化预准备语句的第二语句 -

它将使用userid =“abc”和password =“'OR 1 = 1 OR''='”搜索表中的条目

由于预编译语句是在DB服务器中预先编译的,即首先是空白查询 SELECT * FROM users WHERE userid =? AND password =?被发送到服务器,服务器然后编译它,之后数据(参数)被单独发送到数据库(执行时)。数据,即password = 'OR 1 = 1 OR''='由JDBC Driver作为字符串文字发送。然后,DB服务器强制它用作有效参数而不是sql查询。

答案 2 :(得分:0)

用你的第二个例子,

PreparedStatement stmt = connection.prepareStatement("SELECT * FROM users"
    + " WHERE userid=? AND password=?");
stmt.setString(1, userid);
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery();
     

如果有人输入userId =" abc"和密码=" 1 = 1",因为这也将被视为有效的字符串......

答案是,但是正确转义的字符串文字。因此,密码必须实际上是1 = 1才能工作。需要明确的是,它不受SQL注入的影响,因为这些变量已正确绑定。

根据添加的PreparedStatement.setString(int, String) Javadoc粗体,

  

将指定参数设置为给定的Java String值。当驱动程序将其发送到数据库时,驱动程序将其转换为SQL VARCHAR或LONGVARCHAR (取决于相对于驱动程序对VARCHAR值的限制的参数大小)。 / p>

答案 3 :(得分:0)

使用准备好的声明,您的请求将是:

SELECT * FROM users WHERE userId = \"abc\" AND password = \"1=1\"