关于sql注入漏洞的解决方案

最近一个老项目 扫描漏洞发现某查询接口有sql注入风险

GET /api/tbNews/list?columnId=14355664&current=1&isPush=yes&keyword=&newsSort=&size=5&sort=if(ascii(substr(database(),1,1))=119,sleep(5),1) HTTP/1.1
X-Requested-With: XMLHttpRequest
Referer: https://xxxxx.com/
Accept: application/json, text/plain, */*
Accept-Encoding: gzip,deflate,br
User-Agent: User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)
Host: wjdc.zhwxd.net
Connection: keep-alive

重点看sort参数,接口支持根据传入的字段去排序,

参数含义解析
if(condition, true_expr, false_expr):MySQL 中的条件判断函数。
substr(database(),1,1):截取当前数据库名的第一个字符。
ascii(...):获取该字符的 ASCII 码。
sleep(5):如果条件成立,则让数据库延迟响应 5 秒。
1:如果条件不成立则返回 1,继续执行。
攻击者通过观察响应是否延迟,来推测数据库信息(如数据库名、版本等),从而逐步猜解敏感数据。

代码片段如下,对参数sort并未做任何sql参数校验:

if(Stringutls.isempty(tbNewsDTO.getSort())){
queryWrapper.orderByDesc(tbNewsDTO.getSort());
} 
解决方案:对传入参数进行校验,以下是具体方法实现
package com.jeeplus.radio.news.controller.sql;

import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import org.springframework.http.ResponseEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * SQL注入关键字校验工具
 */
public class SQLInjectionValidator {

    // 常见SQL注入关键字(大小写不敏感)
    private static final String SQL_KEYWORDS =
            "\\b(select|insert|update|delete|drop|sort|truncate|alter|create|union|if|>|<|=|%|join|where|and|or|not|exec|xp_cmdshell|count|\\*|chr|mid|master|into|declare|cast|convert" +
                    "|sleep|benchmark|pg_sleep|waitfor delay|getdate" + // 时间盲注
                    "|ascii|substr|substring|user|version|current_user|session_user|system_user|database|schema_name|table_name" + // 信息收集
                    "|load_file|into outfile|into dumpfile|fopen|fwrite" + // 文件操作
                    "|hex|bin|char|unhex|from_base64|convert|cast" + // 编码绕过
                    "|information_schema|sysobjects|pg_catalog|sqlite_master)\\b"; // 系统表

    // 组合正则表达式模式(大小写不敏感)
    private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
            SQL_KEYWORDS,
            Pattern.CASE_INSENSITIVE | Pattern.DOTALL
    );

    /**
     * 校验输入是否包含SQL注入关键字
     * @param input 待校验的输入字符串列表
     * @return true-包含危险字符,false-安全输入
     */
    public static boolean containsSQLInjection(List<String> input) {
        if (CollectionUtil.isEmpty(input)) {
            return false;
        }

        for (String value : input) {
            if (value == null) continue;

            // 跳过空字符串或纯空白字符串
            if (value.trim().isEmpty()) continue;
            // 使用正则表达式进行匹配
            if (SQL_INJECTION_PATTERN.matcher(value).find()) {
                return true;
            }
        }

        return false;
    }

    public static void main(String[] args) {
        // 测试用例
        String keyword = "if";
        String sort = "";
        String newsSort = "new";
        String columnId = "c6ce5248984111ecac7900163e2ebdc5";

        boolean sqlInjection = SQLInjectionValidator.containsSQLInjection(Lists.newArrayList(
                keyword, sort, newsSort, columnId
        ));

        System.out.println("SQL注入检测结果: " + (sqlInjection ? "存在风险" : "安全"));

        // 测试恶意输入
        boolean maliciousTest = SQLInjectionValidator.containsSQLInjection(Lists.newArrayList(
                "SELECT * FROM users",
                "admin' OR 1=1 --",
                "1; DROP TABLE users;"
        ));

        System.out.println("恶意输入检测结果: " + (maliciousTest ? "存在风险" : "安全"));
    }
}

 

 
posted @ 2025-05-29 15:03  Fyy发大财  阅读(55)  评论(0)    收藏  举报