如何将表名作为参数放入 SQL 查询的安全方法是什么?您不能使用PreparedStatement将表名作为参数。可以使用Statement连接字符串以执行带有动态表名的查询,但不建议这样做,因为存在 SQL 注入的风险。做到这一点的最佳方法是什么?
3 回答
最好的方法是:
- 将您的表名放在用于分隔从一个数据库更改为另一个数据库的表名的字符之间
- 并相应地转义提供的表名,以便不再可能进行 SQL 注入。
因此,例如在 MySQL 的情况下,表名的分隔符是反引号字符,我们只需将其加倍即可对其进行转义。
如果您的查询是SELECT foo from bar
,您可以将查询重写为下一个:
String query = String.format("SELECT foo from `%s`", tableName.replace("`", "``"));
通过这种方式,您可以注入表的名称,而不会冒看到某些恶意代码被注入的风险。
我会尝试解决设计问题,因此您不必动态设置表名。如果这是不可能的,我会选择一种设计,您可以管理可用表的列表,用户从那里选择一个,按 ID,这样您就可以从所选 id 中检索真实的表名并用它替换表名占位符,避免在表名替换中出现任何sql注入的机会。
在动态 JDBC 查询中只允许实际参数背后有一个基本原理:参数可以来自外部并且可以采用任何值,而表和列名是静态的。
可能存在参数化表或列名的用例,主要是当不同的表具有几乎相同的结构并且由于 DRY 原则您不想重复多次相同的查询而只更改表(或列)名称时。但是在那个用例中,程序员可以完全控制要替换的名称,并且应该仔细测试它们中的任何一个都没有错字 => 这里没有 SQL 注入的可能性,替换表是安全的查询字符串中的名称。
这对于在 Internet 上公开的 Web 应用程序来说是完全不同的,其中查询将使用在表单字段中输入的内容,因为这里任何事情都可能发生,包括用于终止原始无害查询并伪造新的有害查询的半列 => SQL 注入如果您只是连接字符串而不是正确构建参数化查询。
我无法想象表名或列名可能是用户在表单字段中键入的字符串的用例,这将是允许参数化它们的唯一原因。