繁体   English   中英

如何修改代码以避免 SQL 注入攻击?

[英]How can I modify the code to avoid SQL-injection attack?

我需要对两个字段businessNamebusinessAddress实现模糊搜索。 它们都可以是null 如果一个字段是null ,则应基于另一字段进行搜索。

再具体一点,

  • 如果businessName="name"businessAddress="address"然后执行select * from business where businessName like '%name%' and businessAddress like '%address%'
  • 如果businessName=nullbusinessAddress="address"然后执行select * from business where businessAddress like '%address%'
  • 如果businessName=nullbusinessAddress=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 方言的字符串连接运算符。)

然后使用准备好的语句并将businessNamebusinessAddress绑定到变量。

PreparedStatement st = con.prepareStatement(query);
st.setString(1,businessName);
st.setString(2,businessAddress);
ResultSet rs = st.executeQuery();

(添加异常处理。)


或者,如果您的 SQL 方言要求您将NULLLIKE分开处理,则:

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 的回答,我认为还有另外两种方法可以解决您的问题。

  1. 转义用户的输入字符串以避免 sql 注入。 但是这种方式不是 100% 安全的。您可以使用 ESAPI 来执行此操作,请参阅SQL_Injection_Prevention_Cheat_Sheet

  2. 您可以使用 ORM 框架,如 MyBatis。 比如MyBatis有dynamic-sql ,它可以让你根据不同的条件生成不同的sql。 此外,使用#{xxx}而不是${xxx}来防止 sql 注入。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM