【发布时间】:2014-01-10 20:09:45
【问题描述】:
我们有一个 Java 应用程序,它与同一个数据库上的多个 SQL Server 数据库进行通信 盒子。这些数据库的数量和名称各不相同。总的来说,我们几乎只使用带有 CallableStatement 的存储过程来访问数据库。我们非常擅长避免 SQL 注入和使用绑定变量。
唯一需要关注的是数据库名称本身被连接到我们传递给 CallableStatement 的 SQL 中:
"{call [" + dbName + ".dbo." + procName + "(?, ?, ?)}"
procName 使用模板方法模式硬编码到子类中,因此可以保证字符串是安全的。
dbName 是在外部定义的。我尝试将 dbName 设置为各种模式以逃避语法并在我的开发环境中利用它,但没有成功。
我已将其设置为以下以生成以下 SQL 调用(更改表和过程名称以保护无辜者):
securitytest].nx_proc()};delete from poor_victim_table;
变成
{call [securitytest].nx_proc()};delete from poor_victim_table;].dbo.proper_proc_name()}
和
securitytest].nx_proc()};exec('delete from poor_victim_table');
变成
{call [securitytest].nx_proc()};exec('delete from poor_victim_table');].dbo.proper_proc_name(?,?,?,?,?,?,?)}
Incorrect syntax near ')'. 和 poor_victim_table 中的结果仍然有行。我使用过truncate table、drop table 和drop database,当它们不起作用时,我切换到简单的delete 以排除安全设置。
如果我使用带有绑定参数的 proc,我总是会得到预期参数的数量与提供的参数(例如 The index 1 is out of range.)之间的不匹配。
securitytest]};exec('delete from poor_victim_table');
变成
{call [securitytest]};exec('delete from poor_victim_table');].dbo.proper_proc_name(?,?,?,?,?,?,?)}
所有的道路似乎都导致运行时错误,SQL不执行。当然,这很棒。但我想确保它失败是因为它不能成功,而不是因为我没有尝试正确的组合而失败。
流行的观点/都市神话是,使用存储过程可以让您免受 SQL 注入的影响,但在安全性方面,我更愿意不相信这样的绝对语句。
在研究了一段时间后,我想出的最好的就是这个 stackoverflow 问题:SQL injection - no danger on stored procedure call (on iSeries)?。它似乎支持使用 CallableStatement,因为它可以保护您免受 SQL 注入除非您的 proc 代码本身从输入参数中生成动态 SQL。
所以,我向社区提出的问题是,假设 proc 中的 SQL 代码是安全的,那么在 JDBC 中使用 CallableStatement 真的可以防止 SQL 注入吗?或者 SQL Server 驱动程序是否以阻止它的方式解析字符串,但其他驱动程序可能不会?还是我不够努力?
如果它是安全的,如何保证?是不是因为使用{ call blah(?) } 的抽象语法,它不是真正的SQL,而是被翻译成SQL?
【问题讨论】:
标签: stored-procedures jdbc sql-injection callable-statement