针对SQL注入的预备语句效果

时间:2018-05-09 19:26:34

标签: java sql prepared-statement sql-injection

例如,我有以下代码:

import java.sql.*; ...
public void main (string[] args){ 
try {
 Class.forName („COM.ibm.db2.jdbc.net.DB2Driver“);} catch (ClassNotFoundException e) {//error handling}
try {
    String url = "jdbc:db2://host:6789/myDB2"
    Connection con = DriverManager.getConnection(url, "login", "password");
    PreparedStatement pStmt = con.prepareStatement("UPDATE PERS SET Salary=Salary*2.0 WHERE PNR=?"

    pStmt.setInt (1, 35);
    pStmt.executeUpdate();

    pStmt.setString (1, args[0]); 
    pStmt.executeUpdate();

    con.close();
    } catch (SQLException e) { //error handling}
}

据推测,我们的表格如下:

+--------+----------+-----------+
|PNR     |Name      |Salary     |
+--------+----------+-----------+
|34      |Tim       |20000      |
+--------+----------+-----------+
|35      |John      |45000      |
+--------+----------+-----------+

我很难预测如果会发生什么:

args[0]="35 OR Salary<100000" 

setString命令是否将args[0]替换为35 OR Salary < 100000,然后所有工资记录都翻了一倍?

2 个答案:

答案 0 :(得分:2)

这不会导致SQL注入问题。它将转换为:

UPDATE PERS SET Salary=Salary*2.0 WHERE PNR='35 OR Salary<100000'

插入的引号将使您免于SQL注入。我简化了一点。 JDBC实现确定PreparedStatement转换为真实SQL查询的准确程度。它实际上并不一定将其转换为上述SQL。但这是防止攻击的一种方式。

但是要小心。如果您使用用户输入来创建SQL,您仍然容易受到SQL注入的影响。只要您仅使用用户输入来呼叫.setXYZ()参数,您就可以安全地使用它。

答案 1 :(得分:2)

服务器端准备语句

SQL参数有助于避免SQL注入,因为参数的值根本不与SQL查询结合使用。带参数占位符的SQL查询被发送到MySQL服务器,在那里进行解析和分析。它执行的操作包括检查您编写的有效SQL语法,您引用的表和列是否存在,以及您是否具有访问这些表和列的正确权限。

这就是参数不能用于表名或列名或其他语法的原因。因为验证发生在参数仍留作占位符时。稍后将发送参数的值,因此验证必须假定参数必须仅替换SQL查询中的单个标量值。

在此之后,查询作为非文本数据结构存储在MySQL服务器内部。它不再是SQL,它只是MySQL代码中的许多内部对象。您使用?的地方成为MySQL知道需要在执行查询之前提供值的查询元素。

运行pStmt.executeUpdate()时,绑定到参数的变量值将发送到MySQL服务器。它们在查询的非文本表示中填充到占位符中。

这样,直到解析完成后才会合并参数值,因此参数内容无法更改SQL语法。它只会像单个字符串一样影响SQL查询,就好像有一种引号分隔符不能被参数内容中不匹配的引号字符破坏。

查询参数是防止SQL注入的可靠方法。

模拟准备语句

有些驱动程序会实现&#34;模拟&#34;准备好的声明这意味着它对传递给prepareStatement()的SQL查询没有任何作用,除了将SQL字符串保存在JDBC驱动程序中(在客户端)。它此时不会将SQL查询发送到服务器。

然后,当您运行executeUpdate()时,您的变量将插入到SQL字符串中的参数占位符中,并将完整字符串发送到服务器。然后MySQL服务器解析组合的SQL查询,带有参数值和all。 MySQL服务器甚至无法告诉哪些值是原始SQL查询中的文字值,哪些值组合为参数。它们都显示为解析器的文字值。

在这种情况下,您必须相信JDBC驱动程序确实正确转义,因此参数内容中的引号和其他字符不能混淆SQL解析器。驱动程序应经过良好测试,以处理所有情况,如特殊字符集,十六进制编码的引号字符和其他欺骗方法。