![](/img/trans.png)
[英]How can I avoid ZAP SQL Injection alerts if my application is already secured against that attack?
[英]How can I modify the code to avoid SQL-injection attack?
我需要对两个字段businessName
和businessAddress
实现模糊搜索。 它们都可以是null
。 如果一个字段是null
,则应基于另一字段进行搜索。
再具体一点,
businessName="name"
和businessAddress="address"
然后执行select * from business where businessName like '%name%' and businessAddress like '%address%'
businessName=null
和businessAddress="address"
然后执行select * from business where businessAddress like '%address%'
businessName=null
和businessAddress=null
然后select * from business
我的代码:
StringBuilder sb = new StringBuilder("select * from business where 1=1 ");
if (businessName != null) {
sb.append("and businessName like '%" + businessName + "%' ");
}
if (businessAddress != null) {
sb.append("and businessAddress like '%" + businessAddress + "%' ");
}
try {
con = DBUtil.getConnection();
pst = con.prepareStatement(sb.toString());
rs = pst.executeQuery();
} ...
显然它有受到 SQL 注入攻击的危险。 我知道方法prepareStatement.setString()
可以避免攻击,但是在验证之前字段的数量是不确定的。
我该如何修改它? 每个案例的单独方法或如下代码看起来很难看。
if(businessName!=null){
if(businessAddress!=null){
sql = ...;
}else {
sql = ...;
}
else{
...
永远不要将值连接到这样的查询字符串中。 执行查询时,始终使用带参数的预处理语句,尤其是使用用户来源的值。
对于您的情况,一个简单的解决方案是为您添加的每个参数使用值列表,然后在执行之前设置为这些参数收集的值:
StringBuilder sb = new StringBuilder("select * from business where 1=1 ");
List<String> parameters = new ArrayList<>();
if (businessName != null) {
sb.append("and businessName like '%' || ? || '%' ");
parameters.add(businessName);
}
if (businessAddress != null) {
sb.append("and businessAddress like '%' || ? || '%' ");
parameters.add(businessAddress)
}
try (Connection con = DBUtil.getConnection();
PreparedStatement pst = con.prepareStatement(sb.toString())) {
int index = 1;
for (String parameter : parameters) {
pst.setString(index++, parameter);
}
try (ResultSet rs = pst.executeQuery()) {
// ...
}
}
如果您有不同类型的参数,请改用List<Object>
和setObject
。
MT0 答案中的解决方案也有效,但并非所有数据库系统都能很好地优化该类型的查询(特别是如果您有很多这样的条件),这可能会影响性能。 仅在少数情况下,MT0 的解决方案更具可读性,同时具有相同/相似的性能。
您不需要动态 SQL 并且可以在查询中使用绑定变量:
String query = "select * from business where businessName LIKE '%' || ? || '%' AND businessAddress LIKE '%' || ? || '%'";
(假设||
是您的 SQL 方言的字符串连接运算符。)
然后使用准备好的语句并将businessName
和businessAddress
绑定到变量。
PreparedStatement st = con.prepareStatement(query);
st.setString(1,businessName);
st.setString(2,businessAddress);
ResultSet rs = st.executeQuery();
(添加异常处理。)
或者,如果您的 SQL 方言要求您将NULL
与LIKE
分开处理,则:
String query = "select * from business
where (:name IS NULL OR businessName LIKE '%' || :name || '%')
AND (:addr IS NULL OR businessAddress LIKE '%' || :addr || '%')";
并使用命名绑定变量:name
和:addr
(或使用?
传递值两次)。
除了 Mark Rotteveel 的回答,我认为还有另外两种方法可以解决您的问题。
转义用户的输入字符串以避免 sql 注入。 但是这种方式不是 100% 安全的。您可以使用 ESAPI 来执行此操作,请参阅SQL_Injection_Prevention_Cheat_Sheet 。
您可以使用 ORM 框架,如 MyBatis。 比如MyBatis有dynamic-sql ,它可以让你根据不同的条件生成不同的sql。 此外,使用#{xxx}
而不是${xxx}
来防止 sql 注入。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.