3

We have a Java application that communicates with multiple SQL Server databases on the same box. The number of and names of these databases vary. By and large, we use almost exclusively stored procedures with CallableStatement to access the databases. We are extremely good about avoiding SQL injection and using bind variables.

The only area of concern is that the database name itself is concatenated into the SQL that we pass to the CallableStatement as such:

"{call [" + dbName + ".dbo." + procName + "(?, ?, ?)}"

procName is hard-coded into child classes using a template method pattern, so that string is guaranteed safe.

dbName is defined externally. I have tried setting dbName to all sorts of patterns to escape the syntax and exploit this on my development environment and have been unsuccessful.

I have set it to the following to produce the following SQL calls (table and proc names changed to protect the innocent):

securitytest].nx_proc()};delete from poor_victim_table;

becomes

{call [securitytest].nx_proc()};delete from poor_victim_table;].dbo.proper_proc_name()}

and

securitytest].nx_proc()};exec('delete from poor_victim_table');

becomes

{call [securitytest].nx_proc()};exec('delete from poor_victim_table');].dbo.proper_proc_name(?,?,?,?,?,?,?)}

Results in Incorrect syntax near ')'. and poor_victim_table still has rows. I have used truncate table, drop table and drop database and when they didn't work, I switched to simple delete to rule out security settings.

If I use a proc that takes bind parameters, I always get a mismatch between the number of expected parameters and supplied parameters such as The index 1 is out of range..

securitytest]};exec('delete from poor_victim_table');

becomes

{call [securitytest]};exec('delete from poor_victim_table');].dbo.proper_proc_name(?,?,?,?,?,?,?)}

All roads seem to lead to a runtime error and the SQL does not execute. Of course, this is great. But I want to make sure it's failing because it cannot succeed and not failing because I am failing to try the right combination.

The popular opinion / urban myth is that using a stored procedure makes you immune to SQL injection, but I prefer to not trust absolute statements like that when it comes to security.

After researching this for a while, the best I came up with is this stackoverflow question: SQL injection - no danger on stored procedure call (on iSeries)?. It seems to support using CallableStatement because it protects you from SQL injection unless your proc code itself makes dynamic SQL out of an input parameter.

So, my question to the community is, assuming the SQL code in a proc is safe, does using CallableStatement in JDBC really prevent SQL injection? Or does the SQL Server driver parse the string in a way that prevents it, but other drivers may not? Or am I not trying hard enough?

If it is safe, how is that guarantee made? Is it due to the abstract syntax of using { call blah(?) } which is not real SQL, but gets translated to SQL?

4

3 回答 3

2

应该是安全的,但就像你一样,我不相信这一点,特别是如果你使用不同的 JDBC 驱动程序等连接到不同的数据库。

如果我是你,在你发布声明之前,我会确保检查 dbName 是否包含除字母、数字和可能的下划线之外的任何内容。这应该允许所有有效的 dbNames,并防止各种弄乱它。

于 2014-01-10T20:15:13.957 回答
0

流行的观点/都市神话是,使用存储过程可以使您免受 SQL 注入的影响,但在安全性方面,我更喜欢不相信这样的绝对语句。

而且你不相信这样一个笼统的陈述做得很好。但是,该语句需要是合格的/合格的。

看,如果存储过程写得好,它就不会受到 SQL 注入的影响。它允许您控制允许使用哪种 SQL 语句。您可以配置您的生产数据库,使其不允许执行 DML,只允许执行存储过程(从而使您免于意外或故意执行可怕的笛卡尔关节的人。)

但除了编写良好的存储过程之外,调用者还有责任验证和清理输入,而 JDBC 为您提供了一种通过“绑定”参数来实现此目的的方法。

ACallableStatement继承自PreparedStatement,它提供绑定参数的方法。绑定方法会转义传入的参数值,从而使注入几乎不可能。

将存储过程(以及可调用和准备好的语句)视为一把锤子。您可以很好地使用它来敲钉子或压碎拇指。

于 2020-02-12T15:01:14.460 回答
0

检查您的数据库连接网址,我认为这是引用静态数据库,所以如果您在可调用语句中写入数据库名称,每当数据库名称更改时都会产生问题,您的代码就像死(大多数地方要更改),所以不要使用数据库名称在查询中,但您可以为不同的数据库连接或不同的助手类创建不同的对象。

于 2018-05-05T12:37:54.530 回答