java - Prepared Statements如何比Statements更好地防止SQL注入(inject)?

标签 java mysql sql jdbc prepared-statement

背景:我已经开始了一个项目,使用 JDBC 和 MYSQL 来模拟一个书店,全是本地的。为了连接到数据库,我开始使用 Statement,但我开始读到,当多次使用仅更改其参数的查询时,对这些查询使用 PreparedStatement 会更有效。然而,我读得最多的是 PreparedStatements 如何更好地防止 SQL 注入(inject)。

来源: 此线程的答案 here
谷歌
教授

我的问题: 在处理参数化查询时,PreparedStatements 如何比 Statements 更好地防止 SQL 注入(inject),甚至在这方面有所不同?我很困惑,因为如果我理解正确的话,这些值仍然会传递到执行的 SQL 语句中,这只是由程序员来清理输入。

最佳答案

你是对的,你可以自己做所有的卫生工作,这样就可以安全地避免注入(inject)。但这更容易出错,因此更不安全。换句话说,自己动手会引入更多可能导致注入(inject)漏洞的漏洞。

一个问题是转义规则可能因数据库而异。例如,标准 SQL 只允许单引号中的字符串文字 ('foo'),因此您的卫生可能只会避开那些;但是 MySQL 允许双引号中的字符串文字 ("foo"),如果您不对它们进行清理,那么如果您使用 MySQL,就会遇到注入(inject)攻击。

如果您使用 PreparedStatement,该接口(interface)的实现由相应的 JDBC Driver 提供,该实现负责转义您的输入。这意味着清理代码是由编写 JDBC 驱动程序的人作为一个整体编写的,这些人大概知道 DB 的特定转义规则的来龙去脉。他们也很可能比您测试您的手动转义函数更彻底地测试了这些转义规则。

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

public void setString(int idx, String value) {
    String sanitized = ourPrivateSanitizeMethod(value);
    internalSetString(idx, value);
}

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

另一个问题是 myUserInputVar 是否已清理可能不是很明显。采取以下片段:

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

这样安全吗?您不知道,因为代码中没有任何内容表明 name 是否经过清理。而且你不能只是“为了安全起见”重新清理,因为这会改变输入(例如,hello '' world 会变成 hello '' world ).另一方面,准备好的声明 UPDATE user SET name=? WHERE id=? 始终是安全的,因为 PreparedStatement 的实现在将值插入 ? 之前对输入进行了转义。

关于java - Prepared Statements如何比Statements更好地防止SQL注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22310812/

相关文章:

java - Spring AOP,切入点表达式 : annotation with specific param

php - 如何在循环中创建循环...? PHP-MySQLi

php - Order by 和 LIMIT 都不能在 MySQL 查询中协同工作

php - 继续在循环中减去值以获得mysql结果php

sql - Oracle 中的 EXCEPT 关键字

sql - (REDSHIFT) 垂直合并/FIRST_VALUE() 作为聚合

php - 使用 PHP 和 MySQL 使数据库驱动的菜单项在每个用户的基础上可见?

java - 加载多个 AdMob 视频

java - 给 JList 的消息

java - 如何在 Android 的 void 函数中退出?