Java WAF案例

wen java案例 2

本文目录导读:

Java WAF案例

  1. 项目结构
  2. 核心实现

我来为您提供一个完整的Java WAF(Web应用防火墙)实现案例,包含SQL注入、XSS、CSRF防护等功能。

项目结构

java-waf/
├── src/main/java/com/waf/
│   ├── filter/
│   │   └── WafFilter.java
│   ├── rule/
│   │   ├── SqlInjectionRule.java
│   │   ├── XssRule.java
│   │   ├── CsrfRule.java
│   │   └── RuleEngine.java
│   ├── config/
│   │   └── WafConfig.java
│   └── util/
│       └── SecurityUtil.java
└── src/main/resources/
    └── waf-rules.xml

核心实现

1 WAF过滤器

package com.waf.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.logging.Logger;
@WebFilter("/*")
public class WafFilter implements Filter {
    private static final Logger LOG = Logger.getLogger(WafFilter.class.getName());
    private RuleEngine ruleEngine;
    private WafConfig config;
    @Override
    public void init(FilterConfig filterConfig) {
        this.ruleEngine = new RuleEngine();
        this.config = WafConfig.loadConfig();
        LOG.info("WAF Filter initialized");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        if (!(request instanceof HttpServletRequest)) {
            chain.doFilter(request, response);
            return;
        }
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        try {
            // 1. 请求验证
            if (!validateRequest(httpRequest, httpResponse)) {
                return;
            }
            // 2. 包装请求(用于请求清洗)
            WafRequestWrapper wrappedRequest = new WafRequestWrapper(httpRequest);
            // 3. 继续处理
            chain.doFilter(wrappedRequest, response);
        } catch (Exception e) {
            LOG.severe("WAF processing error: " + e.getMessage());
            httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }
    private boolean validateRequest(HttpServletRequest request, 
                                  HttpServletResponse response) throws IOException {
        // 获取请求参数
        Map<String, String[]> parameters = request.getParameterMap();
        String requestUri = request.getRequestURI();
        String method = request.getMethod();
        // 1. SQL注入检测
        if (config.isSqlInjectionEnabled() && 
            ruleEngine.checkSqlInjection(parameters)) {
            handleAttack("SQL Injection", request, response);
            return false;
        }
        // 2. XSS检测
        if (config.isXssEnabled() && 
            ruleEngine.checkXss(parameters)) {
            handleAttack("XSS", request, response);
            return false;
        }
        // 3. CSRF检测
        if (config.isCsrfEnabled() && 
            !ruleEngine.checkCsrf(request)) {
            handleAttack("CSRF", request, response);
            return false;
        }
        // 4. 路径遍历检测
        if (config.isPathTraversalEnabled() && 
            ruleEngine.checkPathTraversal(requestUri)) {
            handleAttack("Path Traversal", request, response);
            return false;
        }
        // 5. 文件上传检测
        if (config.isFileUploadEnabled() && 
            "POST".equalsIgnoreCase(method) && 
            request.getContentType() != null && 
            request.getContentType().contains("multipart/form-data")) {
            if (!ruleEngine.checkFileUpload(request)) {
                handleAttack("Malicious File Upload", request, response);
                return false;
            }
        }
        return true;
    }
    private void handleAttack(String attackType, HttpServletRequest request, 
                            HttpServletResponse response) throws IOException {
        LOG.warning(String.format("Blocked %s attack from IP: %s, URI: %s", 
            attackType, 
            request.getRemoteAddr(), 
            request.getRequestURI()));
        // 记录攻击日志
        logAttack(attackType, request);
        // 返回403
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.getWriter().write("Request blocked by WAF");
    }
    private void logAttack(String attackType, HttpServletRequest request) {
        AttackLog log = new AttackLog();
        log.setAttackType(attackType);
        log.setIp(request.getRemoteAddr());
        log.setUri(request.getRequestURI());
        log.setUserAgent(request.getHeader("User-Agent"));
        log.setTimestamp(new Date());
        log.setParameters(request.getParameterMap());
        // 保存到数据库或文件
        AttackLogger.save(log);
    }
    @Override
    public void destroy() {
        LOG.info("WAF Filter destroyed");
    }
}

2 请求包装器

package com.waf.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.*;
public class WafRequestWrapper extends HttpServletRequestWrapper {
    private Map<String, String[]> sanitizedParameters;
    public WafRequestWrapper(HttpServletRequest request) {
        super(request);
        this.sanitizedParameters = sanitizeParameters(request.getParameterMap());
    }
    @Override
    public String getParameter(String name) {
        String[] values = sanitizedParameters.get(name);
        return values != null && values.length > 0 ? values[0] : null;
    }
    @Override
    public Map<String, String[]> getParameterMap() {
        return sanitizedParameters;
    }
    @Override
    public Enumeration<String> getParameterNames() {
        return Collections.enumeration(sanitizedParameters.keySet());
    }
    @Override
    public String[] getParameterValues(String name) {
        return sanitizedParameters.get(name);
    }
    private Map<String, String[]> sanitizeParameters(Map<String, String[]> parameters) {
        Map<String, String[]> sanitized = new HashMap<>();
        for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
            String[] sanitizedValues = new String[entry.getValue().length];
            for (int i = 0; i < entry.getValue().length; i++) {
                sanitizedValues[i] = SecurityUtil.sanitizeInput(entry.getValue()[i]);
            }
            sanitized.put(entry.getKey(), sanitizedValues);
        }
        return sanitized;
    }
}

3 规则引擎

package com.waf.rule;
import java.util.*;
import java.util.regex.Pattern;
public class RuleEngine {
    private SqlInjectionRule sqlInjectionRule;
    private XssRule xssRule;
    private CsrfRule csrfRule;
    public RuleEngine() {
        this.sqlInjectionRule = new SqlInjectionRule();
        this.xssRule = new XssRule();
        this.csrfRule = new CsrfRule();
    }
    public boolean checkSqlInjection(Map<String, String[]> parameters) {
        return sqlInjectionRule.check(parameters);
    }
    public boolean checkXss(Map<String, String[]> parameters) {
        return xssRule.check(parameters);
    }
    public boolean checkCsrf(HttpServletRequest request) {
        return csrfRule.check(request);
    }
    public boolean checkPathTraversal(String uri) {
        // 检查路径遍历
        String pattern = "(\\.\\./|\\.\\.\\\\)|(\\%2e\\%2e/)";
        return Pattern.compile(pattern, Pattern.CASE_INSENSITIVE).matcher(uri).find();
    }
    public boolean checkFileUpload(HttpServletRequest request) {
        // 文件上传验证
        try {
            String contentType = request.getContentType();
            if (contentType != null && contentType.contains("multipart/form-data")) {
                // 检查文件大小
                long contentLength = request.getContentLengthLong();
                if (contentLength > 10 * 1024 * 1024) { // 10MB limit
                    return false;
                }
                // 检查文件名
                String fileName = extractFileName(request);
                if (fileName != null) {
                    // 验证文件扩展名
                    String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
                    Set<String> allowedExtensions = new HashSet<>(Arrays.asList(
                        "jpg", "jpeg", "png", "gif", "pdf", "doc", "docx", "txt"
                    ));
                    if (!allowedExtensions.contains(extension.toLowerCase())) {
                        return false;
                    }
                    // 检查文件名中的路径遍历
                    if (fileName.contains("..") || fileName.contains("/") || fileName.contains("\\")) {
                        return false;
                    }
                }
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }
    private String extractFileName(HttpServletRequest request) {
        // 从multipart请求中提取文件名
        String header = request.getHeader("Content-Disposition");
        if (header != null && header.contains("filename=")) {
            String fileName = header.substring(header.indexOf("filename=") + 9);
            if (fileName.startsWith("\"")) {
                fileName = fileName.substring(1);
            }
            int endIndex = fileName.indexOf("\"");
            if (endIndex > 0) {
                fileName = fileName.substring(0, endIndex);
            }
            return fileName.trim();
        }
        return null;
    }
}

4 SQL注入检测规则

package com.waf.rule;
import java.util.*;
import java.util.regex.Pattern;
public class SqlInjectionRule {
    // SQL注入关键词
    private static final String[] SQL_KEYWORDS = {
        "SELECT", "INSERT", "UPDATE", "DELETE", "DROP", "UNION", 
        "EXEC", "EXECUTE", "ALTER", "CREATE", "TRUNCATE", "LOAD",
        "INTO", "OUTFILE", "DUMPFILE", "SLEEP", "BENCHMARK",
        "OR", "AND", "NOT", "NULL", "LIKE", "BETWEEN", "IN"
    };
    // SQL注入模式
    private static final Pattern[] SQL_PATTERNS = {
        Pattern.compile("'.*?OR.*?'.*?'.*?=.*?'"),
        Pattern.compile("'.*?AND.*?'.*?'.*?=.*?'"),
        Pattern.compile("--.*?$"),
        Pattern.compile("/\\*.*?\\*/"),
        Pattern.compile("UNION.*?SELECT", Pattern.CASE_INSENSITIVE),
        Pattern.compile("SELECT.*?FROM", Pattern.CASE_INSENSITIVE),
        Pattern.compile("INSERT.*?INTO", Pattern.CASE_INSENSITIVE),
        Pattern.compile("DELETE.*?FROM", Pattern.CASE_INSENSITIVE),
        Pattern.compile("DROP.*?(TABLE|DATABASE)", Pattern.CASE_INSENSITIVE),
        Pattern.compile("EXEC(UTE)?\\s*\\(?", Pattern.CASE_INSENSITIVE),
        Pattern.compile("SLEEP\\s*\\(", Pattern.CASE_INSENSITIVE),
        Pattern.compile("BENCHMARK\\s*\\(", Pattern.CASE_INSENSITIVE),
        Pattern.compile("WAITFOR\\s+DELAY", Pattern.CASE_INSENSITIVE),
        Pattern.compile("0x[0-9a-fA-F]+"), // 十六进制编码
        Pattern.compile("CHAR\\s*\\(\\d+\\)", Pattern.CASE_INSENSITIVE)
    };
    public boolean check(Map<String, String[]> parameters) {
        if (parameters == null || parameters.isEmpty()) {
            return false;
        }
        for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
            String paramName = entry.getKey();
            String[] paramValues = entry.getValue();
            // 排除非用户输入参数
            if (isExcludedParameter(paramName)) {
                continue;
            }
            for (String value : paramValues) {
                if (value != null && containsSqlInjection(value)) {
                    return true;
                }
            }
        }
        return false;
    }
    private boolean containsSqlInjection(String input) {
        // 1. 检查SQL关键词
        String upperInput = input.toUpperCase();
        for (String keyword : SQL_KEYWORDS) {
            // 检查完整的关键词(需要前后有空格或特殊字符)
            Pattern keywordPattern = Pattern.compile(
                "\\b" + Pattern.quote(keyword) + "\\b", 
                Pattern.CASE_INSENSITIVE
            );
            if (keywordPattern.matcher(input).find()) {
                // 进一步验证上下文
                if (hasSqlContext(input, keyword)) {
                    return true;
                }
            }
        }
        // 2. 检查SQL注入模式
        for (Pattern pattern : SQL_PATTERNS) {
            if (pattern.matcher(input).find()) {
                return true;
            }
        }
        // 3. 检查常见的SQL注入特征
        if (hasSqlInjectionFeatures(input)) {
            return true;
        }
        return false;
    }
    private boolean hasSqlContext(String input, String keyword) {
        // 检查是否有SQL语句的上下文环境
        String[] sqlOperators = {"=", "'", "\"", "--", "/*", "*/"};
        for (String operator : sqlOperators) {
            if (input.contains(operator)) {
                return true;
            }
        }
        // 检查是否有多个关键词组合
        int keywordCount = 0;
        String upperInput = input.toUpperCase();
        for (String k : SQL_KEYWORDS) {
            if (upperInput.contains(k)) {
                keywordCount++;
            }
        }
        return keywordCount >= 2;
    }
    private boolean hasSqlInjectionFeatures(String input) {
        // 检查编码混淆
        if (input.contains("%27") || // '
            input.contains("%22") || // "
            input.contains("%3B")) { // ;
            return true;
        }
        // 检查Unicode混淆
        if (input.contains("\\u0027") || // '
            input.contains("\\u0022")) { // "
            return true;
        }
        // 检查注释符号
        if (input.contains("#") && input.length() > 2) {
            return true;
        }
        // 检查布尔注入
        if (Pattern.compile("\\d+\\s*=\\s*\\d+").matcher(input).find() &&
            (input.contains("'") || input.contains("\""))) {
            return true;
        }
        return false;
    }
    private boolean isExcludedParameter(String paramName) {
        // 排除系统参数或已知安全的参数
        Set<String> excludedParams = new HashSet<>(Arrays.asList(
            "_", "callback", "_dc", "page", "limit", "start"
        ));
        return excludedParams.contains(paramName.toLowerCase());
    }
}

5 XSS检测规则

package com.waf.rule;
import java.util.*;
import java.util.regex.Pattern;
public class XssRule {
    // XSS模式列表
    private static final Pattern[] XSS_PATTERNS = {
        // 基本脚本标签
        Pattern.compile("<script[^>]*>.*?</script>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL),
        Pattern.compile("<script[^>]*>", Pattern.CASE_INSENSITIVE),
        // JavaScript事件处理器
        Pattern.compile("on\\w+\\s*=", Pattern.CASE_INSENSITIVE),
        Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
        Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
        Pattern.compile("livescript:", Pattern.CASE_INSENSITIVE),
        // HTML标签属性
        Pattern.compile("<embed[^>]*>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("<object[^>]*>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("<applet[^>]*>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("<iframe[^>]*>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("<frame[^>]*>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("<form[^>]*>", Pattern.CASE_INSENSITIVE),
        // CSS表达式
        Pattern.compile("expression\\s*\\(", Pattern.CASE_INSENSITIVE),
        Pattern.compile("-moz-binding", Pattern.CASE_INSENSITIVE),
        Pattern.compile("behavior\\s*:", Pattern.CASE_INSENSITIVE),
        // 数据URI
        Pattern.compile("data\\s*:", Pattern.CASE_INSENSITIVE),
        // SVG事件
        Pattern.compile("<svg[^>]*>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("onload\\s*=", Pattern.CASE_INSENSITIVE),
        Pattern.compile("onerror\\s*=", Pattern.CASE_INSENSITIVE),
        // HTML编码绕过
        Pattern.compile("&#\\d+;"),
        Pattern.compile("&#x[0-9a-fA-F]+;"),
        Pattern.compile("\\&[a-zA-Z]+\\;"),
        // 其他攻击向量
        Pattern.compile("<[^>]*style\\s*=\\s*['\"].*?expression.*?['\"]",
            Pattern.CASE_INSENSITIVE | Pattern.DOTALL),
        Pattern.compile("document\\.\\w+", Pattern.CASE_INSENSITIVE),
        Pattern.compile("window\\.\\w+", Pattern.CASE_INSENSITIVE),
        Pattern.compile("eval\\s*\\(", Pattern.CASE_INSENSITIVE),
        Pattern.compile("alert\\s*\\(", Pattern.CASE_INSENSITIVE),
        Pattern.compile("confirm\\s*\\(", Pattern.CASE_INSENSITIVE),
        Pattern.compile("prompt\\s*\\(", Pattern.CASE_INSENSITIVE),
    };
    public boolean check(Map<String, String[]> parameters) {
        if (parameters == null || parameters.isEmpty()) {
            return false;
        }
        for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
            for (String value : entry.getValue()) {
                if (value != null && containsXss(value)) {
                    return true;
                }
            }
        }
        return false;
    }
    private boolean containsXss(String input) {
        // 1. 检查XSS模式
        for (Pattern pattern : XSS_PATTERNS) {
            if (pattern.matcher(input).find()) {
                return true;
            }
        }
        // 2. 检查嵌套和混淆
        if (hasObfuscatedXss(input)) {
            return true;
        }
        // 3. 检查字符编码绕过
        if (hasEncodedXss(input)) {
            return true;
        }
        return false;
    }
    private boolean hasObfuscatedXss(String input) {
        // 检查嵌套标签
        if (countOccurrences(input, '<') > 2 && 
            countOccurrences(input, '>') > 2) {
            return true;
        }
        // 检查HTML实体编码
        if (input.contains("&lt;") || input.contains("&gt;") || 
            input.contains("&quot;") || input.contains("&apos;")) {
            // 需要解码后再次检查
            String decoded = SecurityUtil.decodeHtmlEntities(input);
            for (Pattern pattern : XSS_PATTERNS) {
                if (pattern.matcher(decoded).find()) {
                    return true;
                }
            }
        }
        return false;
    }
    private boolean hasEncodedXss(String input) {
        // 检查Unicode编码
        if (input.contains("\\u003c") || // <
            input.contains("\\u003e")) { // >
            return true;
        }
        // 检查Base64编码
        if (input.length() > 10 && isBase64(input)) {
            try {
                String decoded = new String(Base64.getDecoder().decode(input));
                for (Pattern pattern : XSS_PATTERNS) {
                    if (pattern.matcher(decoded).find()) {
                        return true;
                    }
                }
            } catch (Exception e) {
                // 不是有效的Base64编码
            }
        }
        return false;
    }
    private int countOccurrences(String str, char ch) {
        int count = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == ch) {
                count++;
            }
        }
        return count;
    }
    private boolean isBase64(String str) {
        String base64Pattern = "^[A-Za-z0-9+/]+=*$";
        return Pattern.compile(base64Pattern).matcher(str).matches();
    }
}

6 CSRF防护规则

package com.waf.rule;
import javax.servlet.http.HttpServletRequest;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HashSet;
import java.util.Set;
public class CsrfRule {
    private static final String CSRF_TOKEN_HEADER = "X-CSRF-Token";
    private static final String CSRF_TOKEN_PARAM = "_csrf";
    private static final Set<String> SAFE_METHODS = new HashSet<String>() {{
        add("GET");
        add("HEAD");
        add("OPTIONS");
        add("TRACE");
    }};
    private SecureRandom random = new SecureRandom();
    public boolean check(HttpServletRequest request) {
        String method = request.getMethod().toUpperCase();
        // GET请求不检查CSRF
        if (SAFE_METHODS.contains(method)) {
            return true;
        }
        // 从session获取token
        String sessionToken = (String) request.getSession().getAttribute("csrf_token");
        if (sessionToken == null) {
            // 生成新token
            sessionToken = generateToken();
            request.getSession().setAttribute("csrf_token", sessionToken);
            return true; // 首次访问不验证
        }
        // 从请求中获取token
        String requestToken = request.getHeader(CSRF_TOKEN_HEADER);
        if (requestToken == null) {
            requestToken = request.getParameter(CSRF_TOKEN_PARAM);
        }
        // 验证token
        if (requestToken == null || !sessionToken.equals(requestToken)) {
            return false;
        }
        return true;
    }
    public String generateToken() {
        byte[] tokenBytes = new byte[32];
        random.nextBytes(tokenBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes);
    }
    // 验证来源
    public boolean checkReferer(HttpServletRequest request) {
        String referer = request.getHeader("Referer");
        if (referer == null) {
            return false; // 没有Referer的请求可能是CSRF
        }
        String serverHost = request.getServerName();
        int serverPort = request.getServerPort();
        // 构建期望的Referer模式
        String expectedReferer = String.format("http://%s:%d", serverHost, serverPort);
        if (request.isSecure()) {
            expectedReferer = String.format("https://%s:%d", serverHost, serverPort);
        }
        return referer.startsWith(expectedReferer);
    }
    // 检查SameSite Cookie
    public boolean checkSameSiteCookie(HttpServletRequest request) {
        String[] cookies = request.getCookies();
        if (cookies != null) {
            for (String cookie : cookies) {
                // 检查cookie是否设置了SameSite属性
                if (cookie.toLowerCase().contains("samesite")) {
                    return true;
                }
            }
        }
        return false;
    }
}

7 安全工具类

package com.waf.util;
import org.owasp.encoder.Encode;
import java.util.regex.Pattern;
public class SecurityUtil {
    // 输入清洗
    public static String sanitizeInput(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        // 1. 去除空字符
        input = input.replaceAll("\\x00", "");
        // 2. HTML实体编码
        input = Encode.forHtml(input);
        // 3. 转义特殊字符
        input = input.replace("&", "&amp;")
                     .replace("<", "&lt;")
                     .replace(">", "&gt;")
                     .replace("\"", "&quot;")
                     .replace("'", "&#x27;")
                     .replace("/", "&#x2F;");
        // 4. 去除控制字符
        input = input.replaceAll("[\\p{Cntrl}&&[^\\r\\n\\t]]", "");
        // 5. 限制长度
        if (input.length() > 1000) {
            input = input.substring(0, 1000);
        }
        return input;
    }
    // URL安全验证
    public static boolean isValidUrl(String url) {
        if (url == null || url.isEmpty()) {
            return false;
        }
        // URL模式
        String urlPattern = "^(https?|ftp)://[\\w.-]+(:\\d+)?(/[\\w./%-]*)?(\\?[\\w&=-]*)?(#\\w*)?$";
        return Pattern.compile(urlPattern, Pattern.CASE_INSENSITIVE).matcher(url).matches();
    }
    // IP地址验证
    public static boolean isValidIp(String ip) {
        if (ip == null || ip.isEmpty()) {
            return false;
        }
        // IPv4模式
        String ipv4Pattern = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
        // IPv6模式
        String ipv6Pattern = "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$";
        return Pattern.compile(ipv4Pattern).matcher(ip).matches() ||
               Pattern.compile(ipv6Pattern).matcher(ip).matches();
    }
    // HTML实体解码
    public static String decodeHtmlEntities(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        input = input.replace("&lt;", "<")
                     .replace("&gt;", ">")
                     .replace("&amp;", "&")
                     .replace("&quot;", "\"")
                     .replace("&#x27;", "'")
                     .replace("&#x2F;", "/");
        // 解码数字实体
        Pattern numericEntityPattern = Pattern.compile("&#(\\d+);");
        java.util.regex.Matcher matcher = numericEntityPattern.matcher(input);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            int codePoint = Integer.parseInt(matcher.group(1));
            matcher.appendReplacement(sb, String.valueOf((char) codePoint));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    // 文件名安全化
    public static String sanitizeFileName(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "unknown";
        }
        // 移除路径
        fileName = fileName.replaceAll("[/\\\\]", "");
        // 移除非字母数字字符(保留点、下划线、连字符)
        fileName = fileName.replaceAll("[^\\w.-]", "_");
        // 限制长度
        if (fileName.length() > 255) {
            int extensionIndex = fileName.lastIndexOf(".");
            if (extensionIndex > 0) {
                String name = fileName.substring(0, 250);
                String extension = fileName.substring(extensionIndex);
                fileName = name + extension;
            } else {
                fileName = fileName.substring(0, 255);
            }
        }
        return fileName;
    }
    // 敏感数据脱敏
    public static String maskSensitiveData(String data, String type) {
        if (data == null || data.isEmpty()) {
            return data;
        }
        switch (type.toUpperCase()) {
            case "CREDIT_CARD":
                if (data.length() >= 16) {
                    return "****-****-****-" + data.substring(data.length() - 4);
                }
                break;
            case "PHONE":
                if (data.length() >= 11) {
                    return data.substring(0, 3) + "****" + data.substring(data.length() - 4);
                }
                break;
            case "EMAIL":
                int atIndex = data.indexOf("@");
                if (atIndex > 0) {
                    return data.charAt(0) + "****" + data.substring(atIndex - 1);
                }
                break;
            case "ID_CARD":
                if (data.length() >= 18) {
                    return data.substring(0, 4) + "**********" + data.substring(data.length() - 4);
                }
                break;
            default:
                // 默认脱敏
                if (data.length() > 8) {
                    return data.substring(0, 4) + "****" + data.substring(data.length() - 4);
                }
        }
        return "****";
    }
    // 时间盲注检测
    public static boolean checkTimeBasedInjection(String input) {
        if (input == null || input.isEmpty()) {
            return false;
        }
        // 检测时间延迟函数
        Pattern timePattern = Pattern.compile(
            "SLEEP\\s*\\(|" +
            "BENCHMARK\\s*\\(|" +
            "WAITFOR\\s+DELAY|" +
            "pg_sleep\\s*\\(|" +
            "DBMS_LOCK\\.SLEEP|" +
            "\\w+\\.wait\\s*\\(|" +
            "time\\s*\\(.*\\)|" +
            "delay\\s*\\(|" +
            "usleep\\s*\\(",
            Pattern.CASE_INSENSITIVE
        );
        return timePattern.matcher(input).find();
    }
    // 布尔注入检测
    public static boolean checkBooleanInjection(String input) {
        if (input == null || input.isEmpty()) {
            return false;
        }
        // 检测布尔注入模式
        Pattern booleanPattern = Pattern.compile(
            "'.*?OR.*?'.*?=.*?'.*?|" +
            "'.*?AND.*?'.*?=.*?'.*?|" +
            "\\d+\\s*=\\s*\\d+|" +
            "\\d+\\s*!=\\s*\\d+|" +
            "\\d+\\s*<\\s*\\d+|" +
            "\\d+\\s*>\\s*\\d+|" +
            "'\\s*=\\s*'|" +
            "'\\s*!=\\s*'",
            Pattern.CASE_INSENSITIVE
        );
        return booleanPattern.matcher(input).find();
    }
}

8 配置类

package com.waf.config;
import java.io.InputStream;
import java.util.Properties;
import java.util.logging.Logger;
public class WafConfig {
    private static final Logger LOG = Logger.getLogger(WafConfig.class.getName());
    private static final String CONFIG_FILE = "waf.properties";
    private boolean enabled = true;
    private boolean sqlInjectionEnabled = true;
    private boolean xssEnabled = true;
    private boolean csrfEnabled = true;
    private boolean pathTraversalEnabled = true;
    private boolean fileUploadEnabled = true;
    private boolean rateLimitEnabled = false;
    private int maxRequestSize = 10 * 1024 * 1024; // 10MB
    private int rateLimit = 100; // 每秒请求数限制
    private String[] excludedPaths;
    private String[] allowedIpList;
    public static WafConfig loadConfig() {
        WafConfig config = new WafConfig();
        try (InputStream input = WafConfig.class.getClassLoader()
                .getResourceAsStream(CONFIG_FILE)) {
            if (input != null) {
                Properties props = new Properties();
                props.load(input);
                config.setEnabled(Boolean.parseBoolean(
                    props.getProperty("waf.enabled", "true")));
                config.setSqlInjectionEnabled(Boolean.parseBoolean(
                    props.getProperty("waf.sql.injection.enabled", "true")));
                config.setXssEnabled(Boolean.parseBoolean(
                    props.getProperty("waf.xss.enabled", "true")));
                config.setCsrfEnabled(Boolean.parseBoolean(
                    props.getProperty("waf.csrf.enabled", "true")));
                config.setPathTraversalEnabled(Boolean.parseBoolean(
                    props.getProperty("waf.path.traversal.enabled", "true")));
                config.setFileUploadEnabled(Boolean.parseBoolean(
                    props.getProperty("waf.file.upload.enabled", "true")));
                config.setRateLimitEnabled(Boolean.parseBoolean(
                    props.getProperty("waf.rate.limit.enabled", "false")));
                String maxSize = props.getProperty("waf.max.request.size");
                if (maxSize != null) {
                    config.setMaxRequestSize(Integer.parseInt(maxSize));
                }
                String rateLimit = props.getProperty("waf.rate.limit");
                if (rateLimit != null) {
                    config.setRateLimit(Integer.parseInt(rateLimit));
                }
                String excluded = props.getProperty("waf.excluded.paths");
                if (excluded != null) {
                    config.setExcludedPaths(excluded.split(","));
                }
                String allowedIps = props.getProperty("waf.allowed.ips");
                if (allowedIps != null) {
                    config.setAllowedIpList(allowedIps.split(","));
                }
            }
        } catch (Exception e) {
            LOG.warning("Failed to load WAF config, using defaults: " + e.getMessage());
        }
        return config;
    }
    // Getters and Setters
    public boolean isEnabled() { return enabled; }
    public void setEnabled(boolean enabled) { this.enabled = enabled; }
    public boolean isSqlInjectionEnabled() { return sqlInjectionEnabled; }
    public void setSqlInjectionEnabled(boolean enabled) { this.sqlInjectionEnabled = enabled; }
    public boolean isXssEnabled() { return xssEnabled; }
    public void setXssEnabled(boolean enabled) { this.xssEnabled = enabled; }
    public boolean isCsrfEnabled() { return csrfEnabled; }
    public void setCsrfEnabled(boolean enabled) { this.csrfEnabled = enabled; }
    public boolean isPathTraversalEnabled() { return pathTraversalEnabled; }
    public void setPathTraversalEnabled(boolean enabled) { this.pathTraversalEnabled = enabled; }
    public boolean isFileUploadEnabled() { return fileUploadEnabled; }
    public void setFileUploadEnabled(boolean enabled) { this.fileUploadEnabled = enabled; }
    public boolean isRateLimitEnabled() { return rateLimitEnabled; }
    public void setRateLimitEnabled(boolean enabled) { this.rateLimitEnabled = enabled; }
    public int getMaxRequestSize() { return maxRequestSize; }
    public void setMaxRequestSize(int size) { this.maxRequestSize = size; }
    public int getRateLimit() { return rateLimit; }
    public void setRateLimit(int limit) { this.rateLimit = limit; }
    public String[] getExcludedPaths() { return excludedPaths; }
    public void setExcludedPaths(String[] paths) { this.excludedPaths = paths; }
    public String[] getAllowedIpList() { return allowedIpList; }
    public void setAllowedIpList(String[] ips) { this.allowedIpList = ips; }
    // 检查路径是否被排除
    public boolean isExcludedPath(String path) {
        if (excludedPaths == null) {
            return false;
        }
        for (String excludedPath : excludedPaths) {
            if (path.startsWith(excludedPath.trim())) {
                return true;
            }
        }
        return false;
    }
    // 检查IP是否允许
    public boolean isIpAllowed(String ip) {
        if (allowedIpList == null || allowedIpList.length == 0) {
            return true;
        }
        for (String allowedIp : allowedIpList) {
            if (allowedIp.trim().equals(ip)) {
                return true;
            }
        }
        return false;
    }

上一篇Java IAST案例

下一篇当前分类已是最新一篇

抱歉,评论功能暂时关闭!