本文目录导读:

我来为您提供一个完整的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("<") || input.contains(">") ||
input.contains(""") || input.contains("'")) {
// 需要解码后再次检查
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("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace("\"", """)
.replace("'", "'")
.replace("/", "/");
// 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("<", "<")
.replace(">", ">")
.replace("&", "&")
.replace(""", "\"")
.replace("'", "'")
.replace("/", "/");
// 解码数字实体
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;
}