Java 阻止表单生成的SQL中的SQL注入-无PreparedStmts

Java 阻止表单生成的SQL中的SQL注入-无PreparedStmts,java,sql,regex,security,sql-injection,Java,Sql,Regex,Security,Sql Injection,我有一个搜索表,用户可以在其中使用以下类型的筛选器筛选结果: 字段[Name],值[John],删除 规则 字段[姓氏],值[布莱克], 删除规则 字段[有子项],值[是], 删除规则 添加规则 因此,用户将能够设置任意一组过滤器,这将从本质上产生一个完全动态的WHERE子句。将来我还必须实现更复杂的逻辑表达式,比如 其中(姓名=约翰或姓名=尼克)和(姓氏=布莱克或姓氏=伯恩) 在用户可以过滤或不过滤的所有10个字段中,我不知道用户将设置多少个和哪些过滤器。因此,我不能使用预先准备好的语句(

我有一个搜索表,用户可以在其中使用以下类型的筛选器筛选结果:

  • 字段[Name],值[John],删除 规则
  • 字段[姓氏],值[布莱克], 删除规则
  • 字段[有子项],值[是], 删除规则
  • 添加规则
因此,用户将能够设置任意一组过滤器,这将从本质上产生一个完全动态的WHERE子句。将来我还必须实现更复杂的逻辑表达式,比如

其中(姓名=约翰或姓名=尼克)和(姓氏=布莱克或姓氏=伯恩)

在用户可以过滤或不过滤的所有10个字段中,我不知道用户将设置多少个和哪些过滤器。因此,我不能使用预先准备好的语句(它假设我们至少知道WHERE子句中的字段)。这就是为什么准备好的语句不幸是不可能的,我必须用普通的、旧的、生成的SQL来完成


我可以采取什么措施保护应用程序不受SQL注入的影响(REGEX-wise或任何其他方式)?

如果向准备好的语句添加参数,它们将自动转义

conn = pool.getConnection( );
String selectStatement = "SELECT * FROM User WHERE userId = ? ";
PreparedStatement prepStmt = con.prepareStatement(selectStatement);
prepStmt.setString(1, userId);
ResultSet rs = prepStmt.executeQuery();
Java,未经测试

List<String> clauses = new ArrayList<String>();
List<String> binds = new ArrayList<String>();

if (request.name != null) {
    binds.add(request.name);
    clauses.add("NAME = ?");
}

if (request.city != null) {
    binds.add(request.city);
    clauses.add("CITY = ?");
}

...

String whereClause = "";

for(String clause : clauses) {
    if (whereClause.length() > 0) {
        whereClause = whereClause + " AND ";
    }
    whereClause = whereClause + clause;
}

String sql = "SELECT * FROM table WHERE " + whereClause;

PreparedStatement ps = con.prepareStatment(sql);

int col = 1;
for(String bind : binds) {
    ps.setString(col++, bind);
}

ResultSet rs = ps.executeQuery();
List子句=新的ArrayList();
列表绑定=新的ArrayList();
if(request.name!=null){
binds.add(请求.名称);
添加(“名称=?”);
}
if(request.city!=null){
绑定。添加(请求。城市);
添加(“城市=?”);
}
...
字符串whereClause=“”;
for(字符串子句:子句){
if(whereClause.length()>0){
Where子句=Where子句+“和”;
}
Where子句=Where子句+子句;
}
String sql=“从表WHERE”+WHERE子句中选择*;
PreparedStatement ps=con.PrepareStation(sql);
int col=1;
for(字符串绑定:绑定){
ps.setString(col++,bind);
}
结果集rs=ps.executeQuery();


动态构建where子句,但使用参数名进行构建

我不明白为什么准备好的语句是不可能的。因为有10个字段是可过滤的,我不知道用户要过滤多少。因此,我可能只在名称中进行筛选(其中名称='XXX')或在更多字段中进行筛选(其中名称='XXX'和姓氏='YYY'和……)。每个可能的过滤器组合都需要不同的准备语句。这就是为什么准备好的语句在这里是不可能的。然后动态地构造和绑定准备好的语句。拥有数量可变的参数从来都不是一个障碍,而且实际上比必须通过字符串连接处理查询构建更容易,我假设您以前正在这样做。您是对的,我一看到答案就明白了。此查询假设记录是按用户ID过滤的。如果它们是按名称过滤的呢?还是名字和姓氏?还是通过姓名和电子邮件?还是通过电子邮件?每一项都需要一份不同的准备好的声明。我有10个字段,用户可以(也可以不)过滤(以及它们的组合)。那个这就是为什么事先准备好的陈述在这里是不可能的。你是对的,我一看到答案就明白了。另一个答案更清楚一点,所以我在上面做了标记。(+1)听起来不错,但我总是使用StringBuilder而不是字符串连接。这正是StringBuilder的用武之地。这绝对是最好的方法。将列名列为白名单,然后遍历输入,在准备好的语句上设置参数。我也喜欢您的
绑定列表。好主意。谢谢克里斯,要是有办法把答案分开就好了。威尔快了2分钟。(+1)