我们有一个 Java 应用程序可以与同一台服务器上的多个 SQL Server 数据库进行通信 盒子。这些数据库的数量和名称各不相同。总的来说,我们几乎完全使用带有 CallableStatement 的存储过程来访问数据库。我们非常擅长避免 SQL 注入(inject)和使用绑定(bind)变量。
唯一需要关注的是数据库名称本身连接到我们传递给 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(?,?,?,?,?,?,?)}
导致 ')' 附近的语法不正确。
和 poor_victim_table
仍然有行。我使用过truncate table
、drop table
和drop database
,当它们不起作用时,我切换到简单的delete
排除安全设置。
如果我使用带有绑定(bind)参数的过程,我总是会在预期参数的数量和提供的参数之间出现不匹配,例如 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 注入(inject)的影响,但在安全性方面,我宁愿不要相信这样的绝对陈述。
研究了一段时间后,我想到的最好的是这个 stackoverflow 问题:SQL injection - no danger on stored procedure call (on iSeries)? .它似乎支持使用 CallableStatement,因为它可以保护您免受 SQL 注入(inject)除非您的过程代码本身从输入参数中生成动态 SQL。
因此,我向社区提出的问题是,假设 proc 中的 SQL 代码是安全的,那么在 JDBC 中使用 CallableStatement 真的能防止 SQL 注入(inject)吗?或者 SQL Server 驱动程序是否以阻止它的方式解析字符串,但其他驱动程序可能不会?还是我不够努力?
如果是安全的,如何保证?是否由于使用 { call blah(?) }
的抽象语法不是真正的 SQL,而是被转换为 SQL?
最佳答案
您应该是安全的,但就像您一样,我不相信这一点,尤其是当您使用不同的 JDBC 驱动程序等连接到不同的数据库时。
如果我是你,在你发布声明之前,我会确保检查 dbName 是否包含除字母、数字和可能的下划线之外的任何内容。这应该允许所有有效的 dbNames,并防止各种困惑。
关于stored-procedures - CallableStatement 真的不受 SQL 注入(inject)的影响吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21053535/