如何在动态查询中保护自己免受SQL注入?

use*_*654 4 java sql oracle sql-injection

我的应用程序获取对数据库的String对象查询.例如String query = EMAIL like '% test%' and USER_NAME like '% user%'.查询是动态构建的,我不知道它的结构,所以我无法利用PrepareStatement.有谁知道在这种情况下防止SQL注入的方式?

数据库:Oracle
语言:Java 1.6

请帮忙.

Joa*_*uer 9

即使你不知道结构,你也可以使用PreparedStatement.让我用一个简单的例子来演示:

List<Object> arguments = new ArrayList<Object>();
String sql = "SELECT * FROM user WHERE someCondition = ?";
if (queryOnEmail) {
  sql = sql + " AND email LIKE ?";
  arguments.add(email);
}
if (queryOnUserName) {
  sql = sql + " AND user_name LIKE ?";
  arguments.add(userName);
}
PreparedStatement stmt = con.prepareStatement(sql);
int i = 1;
for(Object o : arguments) {
  stmt.setObject(i, o);
  i++;
}
Run Code Online (Sandbox Code Playgroud)

当然,您可以将此SQL + arguments构造包装到其自己的类中,以简化其用法.

  • @ user612925:不是真的:一个恶意注入的参数可能会修改你的查询仍然只是查询那些字段但是你没想到的方式(例如它可以添加`"OR EMAIL IS NOT NULL"`). (3认同)
  • 是的,我理解:你将不得不**改变构造查询字符串的方式,否则你将无法避免SQL注入攻击.**如果**字符串与您显示的完全一致,则SQL注入已经发生,您无法在执行SQL之前可靠地"修复"它. (2认同)
  • 只是一个小提示:当你想动态地构建你的SQL时,当你用`1 = 1`启动where子句时,它通常会有所帮助.这有帮助,因为如果它是第一个条件(必须没有"AND")或后来的条件(必须有"AND"),那么你就不必关心它.即使用它作为基本SQL:`SELECT*FROM user WHERE 1 = 1`并使用`AND`动态添加所有需要的条件.这有助于避免使用MUCH样板代码来检查是否需要"AND". (2认同)

dbf*_*dbf 0

当您构建查询并使用PreparedStatement时,您可以动态构建语句的变量列表。