首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Web 入侵檢測與防禦:基於 Filter 的限流實戰

     編輯:Java 相關知識

業務場景:為什麼需要應用層入侵檢測?

Web 應用常面臨:惡意刷單、暴力破解、CC 攻擊 (高併發請求耗盡資源)、爬蟲盜刷資料。硬體防火牆/ WAF (Web Application Firewall) 雖強,但成本高、規則通用、難以感知業務語義。**應用層軟體檢測** 可精準識別「同一用戶/ IP 短時間高頻訪問」、「登入失敗超限」、「異常 User-Agent」等業務異常,配合攔截、驗證碼、封禁、降級等動態響應,是纏深防禦體系的關鍵一環。

核心設計:濾波器鏈前置攔截

Java Web 兩大架構下的切入點:

  • 傳統 Servlet/JSP:實作 javax.servlet.Filter,在 web.xml 或 @WebFilter 配置 /*,**確保位於 Filter 鏈最前端** (Spring Boot 可用 @Order(Ordered.HIGHEST_PRECEDENCE))。
  • Struts/Spring MVC/EasyJWeb 等框架:框架單一入口 (如 DispatcherServlet, ActionServlet) 內部攔截器 / 攔截器鏈 / 核心 Controller 執行前調用檢測邏輯。

實戰組件設計 (參考 EasyJWeb 實現)

1. 用戶訪問資訊實體 UserConnect

@Data
public class UserConnect {
    private String userName;          // 用戶名/匿名標識
    private String ip;                // 客戶端 IP (注意反向代理下取 X-Forwarded-For)
    private LocalDateTime firstFailureTime; // 首次異常時間
    private LocalDateTime lastAccessTime;   // 最近訪問時間
    private int failureCount;         // 異常/高頻計數
    private int status = 0;           // 0 正常, -1 封禁
}

2. 核心檢測管理器 UserConnectManage (單例/執行緒安全)

@Component
public class UserConnectManage {
    // 配置參數 (支援動態刷新 @ConfigurationProperties)
    private int maxFailureTimes = 10;          // 最大允許異常次數
    private long maxFailureIntervalMs = 10_000; // 統計時間窗口 (毫秒)
    private long waitIntervalMs = 60_000;       // 封禁冷卻時間
    private int maxOnlineUsers = 10_000;        // 記憶體保護上限

    // 核心儲存:ConcurrentHashMap 高併發安全
    private final Map userMap = new ConcurrentHashMap<>();

    // 定時清理任務 (每 2 秒掃描)
    @Scheduled(fixedRate = 2000)
    public void cleanExpired() {
        long now = System.currentTimeMillis();
        userMap.entrySet().removeIf(entry -> {
            UserConnect uc = entry.getValue();
            // 清理超時記錄
            if (now - uc.getFirstFailureTime().toInstant(ZoneOffset.ofHours(8)).toEpochMilli() > maxFailureIntervalMs) {
                return true;
            }
            // 記憶體保護:超限隨機淘汰 50%
            if (userMap.size() > maxOnlineUsers) {
                // 簡單策略:隨機清理一半 (生產建議用 LRU/Caffeine)
            }
            return false;
        });
    }

    /**
     * 核心校驗入口:返回 true 放行,false 攔截
     */
    public synchronized boolean checkLoginValidate(String ip, String userName) {
        String key = ip + ":" + userName;
        UserConnect uc = userMap.computeIfAbsent(key, k -> {
            UserConnect n = new UserConnect();
            n.setIp(ip); n.setUserName(userName);
            n.setFirstFailureTime(LocalDateTime.now());
            n.setFailureCount(0);
            return n;
        });

        long nowMs = System.currentTimeMillis();
        long firstMs = uc.getFirstFailureTime().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();

        // 已封禁且未過冷卻期
        if (uc.getStatus() == -1 && (nowMs - firstMs < maxFailureIntervalMs + waitIntervalMs)) {
            return false;
        }

        // 封禁期過,重置狀態
        if (uc.getStatus() == -1) {
            uc.setStatus(0);
            uc.setFailureCount(0);
            uc.setFirstFailureTime(LocalDateTime.now());
        }

        // 計數+1
        uc.setFailureCount(uc.getFailureCount() + 1);
        uc.setLastAccessTime(LocalDateTime.now());

        // 判斷是否超限
        if (uc.getFailureCount() > maxFailureTimes && (nowMs - firstMs < maxFailureIntervalMs)) {
            uc.setStatus(-1); // 封禁
            return false;
        }
        return true;
    }

    // 管理介面:重置/移除/清空/動態調參...
}

3. Filter 整合範例

@WebFilter(urlPatterns = "/*", dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD})
@Order(Ordered.HIGHEST_PRECEDENCE)
public class IntrusionDetectionFilter implements Filter {
    @Autowired private UserConnectManage detector;

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        String ip = getRealIp(request); // 處理 Nginx 反代頭
        String user = Optional.ofNullable(request.getRemoteUser()).orElse("anonymous");

        if (!detector.checkLoginValidate(ip, user)) {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
            response.getWriter().write(
                "{\"code\":429,\"msg\":\"訪問過於頻繁,請 " + detector.getWaitIntervalMs()/1000 + " 秒後再試\"}"
            );
            return; // 直接截斷鏈
        }
        chain.doFilter(request, response); // 放行
    }

    private String getRealIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip.split(",")[0].trim(); // 取第一個非代理 IP
    }
}

生產級增強方案

痛點進階方案
單機記憶體限制、重啟丟失**Redis + Lua 腳本** 原子操作計數器、滑動窗口、分散式鎖;鍵設計 ratelimit:{ip}:{api},TTL 自動過期。
固定窗口邊界突刺**滑動窗口 / 滑動日誌 / 令牌桶 / 漏桶** 演算法 (Guava RateLimiter、Resilience4j、Sentinel)。
僅限流無風險識別整合 **設備指紋 (FP)**、行為分析 (滑鼠軌跡、點擊間隔)、威脅情報庫 (惡意 IP 庫)、驗證碼 (圖形/滑塊/行為) 多因子驗證。
誤傷正常用戶白名單機制 (內部 IP、合作夥伴)、分級策略 (登入/支付/查詢不同閾值)、優雅降級 (返回靜態頁/快取而非硬拒)。
可觀測性缺失埋點 Metrics (QPS、拒絕率、封禁數)、Grafana 儀表板、告警規則 (連續 5 分鐘拒絕率 > 20% 觸發 P0)。

架構定位:纏深防禦體系中的一環

客戶端 → [CDN/WAF] → [Nginx 限流/黑白名單] → [API Gateway 限流/鑒權] 
    → [應用層 Filter 入侵檢測/業務風控] → [業務邏輯] → [資料庫/快取]

各層職責不同、顆粒度遞增,共同構建高可用、可演進的安全防線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved