准备语句如何比语句更好地防止SQL注入?

Mat*_*t C 4 java mysql sql jdbc prepared-statement

背景:我已经开始使用JDBC和MYSQL来模拟书店,所有本地项目.为了连接到数据库,我开始使用Statement,但我开始读到,当多次使用查询只更改其参数时,为这些查询使用PreparedStatement会更有效.但是,我最常阅读的优点是PreparedStatements如何更好地防止SQL注入.

来源: 回答这个线程在这里
谷歌
教授

我的问题: 在处理参数化查询时,PreparedStatements如何更好地阻止SQL注入,甚至不同于语句?我很困惑,因为如果我理解正确,值仍然会被传递到执行的SQL语句中,这只取决于程序员清理输入.

ysh*_*vit 6

你是对的,你可以自己做所有的卫生,因此注射安全.但这更容易出错,因此不太安全.换句话说,自己动手会为可能导致注入漏洞的bug提供更多机会.

一个问题是转义规则可能因DB而异.例如,标准SQL只允许使用单引号('foo')中的字符串文字,因此您的卫生设施可能只会逃避那些; 但是MySQL允许使用双引号("foo")中的字符串文字,如果你不对它们进行消毒,如果你使用MySQL,你将会受到注入攻击.

如果使用PreparedStatement,则该接口的实现由相应的JDBC提供Driver,并且该实现负责转义您的输入.这意味着清理代码是由编写JDBC驱动程序的人编写的,这些人可能知道数据库特定的转义规则的来龙去脉.他们也很可能比你测试手动转义函数更彻底地测试那些逃避规则.

因此,如果您编写preparedStatement.setString(1, name),该方法的实现(同样,由您正在使用的数据库的JDBC驱动程序人员编写)可能大致如下:

public void setString(int idx, String value) {
    String sanitized = ourPrivateSanitizeMethod(value);
    internalSetString(idx, value);
}
Run Code Online (Sandbox Code Playgroud)

(请记住,上面的代码是一个非常粗略的草图;许多JDBC驱动程序实际上处理它的方式完全不同,但原理基本相同.)

另一个问题是,是否myUserInputVar已经消毒可能是不明显的.请看以下代码段:

private void updateUser(int name, String id) throws SQLException {
    myStat.executeUpdate("UPDATE user SET name=" + name + " WHERE id=" + id);
}
Run Code Online (Sandbox Code Playgroud)

这样安全吗?您不知道,因为代码中没有任何内容表明是否name已经过消毒.而且你不能只是重新消毒"保持安全",因为这会改变输入(例如,hello ' world会变成hello '' world).另一方面,准备好的语句UPDATE user SET name=? WHERE id=?总是安全的,因为它PreparedStatement的实现在将值插入到输入之前逃避了输入?.