防火墙 过滤 XSS SQL 攻击

v1.4.1
Parker 4 years ago
parent e1ac746f3f
commit 06dab595a5

@ -0,0 +1,89 @@
package org.opsli.core.waf;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* Xss
*
* @author 951755883@qq.com
* @date 2018/10/26
*/
@ConfigurationProperties(prefix = XssProperties.XSS)
public class XssProperties {
public static final String XSS = "xss";
/**
* xss
*/
boolean enable = false;
/**
* sql
*/
boolean sqlFilter = false;
/**
* xss
*/
String name = "xssFilter";
/**
* xss
*/
String[] urlPatterns = {"/*"};
List<String> urlExclusion;
/**
*
*/
int order = 0;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getUrlPatterns() {
return urlPatterns;
}
public void setUrlPatterns(String[] urlPatterns) {
this.urlPatterns = urlPatterns;
}
public List<String> getUrlExclusion() {
return urlExclusion;
}
public void setUrlExclusion(List<String> urlExclusion) {
this.urlExclusion = urlExclusion;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public boolean isSqlFilter() {
return sqlFilter;
}
public void setSqlFilter(boolean sqlFilter) {
this.sqlFilter = sqlFilter;
}
}

@ -0,0 +1,65 @@
package org.opsli.core.waf.filter;
import org.opsli.core.waf.servlet.WafHttpServletRequestWrapper;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
/**
*
*
* @author Parker
* @date 2020-10-09
*/
public class WafFilter implements Filter {
private boolean enableXssFilter = false;
private boolean enableSqlFilter = false;
private List<String> urlExclusion;
@Override
public void init(FilterConfig config) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String servletPath = httpServletRequest.getServletPath();
// 如果是排除url 则放行
if (urlExclusion != null && urlExclusion.contains(servletPath)) {
chain.doFilter(request, response);
} else {
// 执行过滤
chain.doFilter(
new WafHttpServletRequestWrapper((HttpServletRequest) request, enableXssFilter, enableSqlFilter),
response);
}
}
@Override
public void destroy() {
}
// ============================
public void setEnableXssFilter(boolean enableXssFilter) {
this.enableXssFilter = enableXssFilter;
}
public void setEnableSqlFilter(boolean enableSqlFilter) {
this.enableSqlFilter = enableSqlFilter;
}
public void setUrlExclusion(List<String> urlExclusion) {
this.urlExclusion = urlExclusion;
}
}

@ -0,0 +1,217 @@
package org.opsli.core.waf.servlet;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.opsli.common.constants.TokenConstants;
import org.opsli.common.exception.WafException;
import org.opsli.core.waf.util.XSSFilterKit;
import org.opsli.core.waf.util.SQLFilterKit;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
*
* @author Parker
* @date 2020-10-09
*/
@Slf4j
public class WafHttpServletRequestWrapper extends HttpServletRequestWrapper {
/** 头消息类型 */
private static final String CONTENT_TYPE = "Content-Type";
private static final List<String> CONTENT_TYPE_LIST = Lists.newArrayList();
static {
CONTENT_TYPE_LIST.add("application/json");
CONTENT_TYPE_LIST.add("application/json;charset=UTF-8");
CONTENT_TYPE_LIST.add("application/x-www-form-urlencoded;charset=UTF-8");
}
/**
* HttpServletRequest
*/
HttpServletRequest orgRequest;
/** Xss 攻击防护 */
private final boolean enableXssFilter;
/** SQL 攻击防护 */
private final boolean enableSqlFilter;
public WafHttpServletRequestWrapper(HttpServletRequest request, boolean enableXssFilter, boolean enableSqlFilter) {
super(request);
orgRequest = request;
this.enableXssFilter = enableXssFilter;
this.enableSqlFilter = enableSqlFilter;
}
/**
* json
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
//非json类型直接返回
if (!CONTENT_TYPE_LIST.contains(super.getHeader(CONTENT_TYPE))) {
return super.getInputStream();
}
//为空,直接返回
String json = StreamUtils.copyToString(super.getInputStream(), StandardCharsets.UTF_8);
if (StringUtils.isEmpty(json)) {
return super.getInputStream();
}
ByteArrayInputStream bis;
try {
// 防火墙过滤
JSONObject jsonObject = JSONObject.parseObject(json);
Set<String> keys = jsonObject.keySet();
for (String key : keys) {
jsonObject.put(key,
filterParamString(String.valueOf(jsonObject.get(key)))
);
}
json = jsonObject.toJSONString();
}catch (WafException e){
throw e;
}catch (Exception e){
log.error(e.getMessage(),e);
}finally {
bis = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
}
return new ServletInputStream() {
@Override
public boolean isFinished() {
return true;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return bis.read();
}
};
}
@Override
public String getParameter(String name) {
String value = super.getParameter(filterParamString(name));
if (!StringUtils.isEmpty(value) && !TokenConstants.ACCESS_TOKEN.equals(name)) {
// 防火墙过滤
value = filterParamString(value);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] parameters = super.getParameterValues(name);
if (parameters == null || parameters.length == 0) {
return null;
}
for (int i = 0; i < parameters.length; i++) {
if (!TokenConstants.ACCESS_TOKEN.equals(name)) {
if(parameters[i] != null){
// 防火墙过滤
parameters[i] = filterParamString(parameters[i]);
}
}
}
return parameters;
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> map = new LinkedHashMap<>();
Map<String, String[]> parameters = super.getParameterMap();
for (String key : parameters.keySet()) {
String[] values = parameters.get(key);
if (!TokenConstants.ACCESS_TOKEN.equals(key)) {
for (int i = 0; i < values.length; i++) {
if(values[i] != null){
// 防火墙过滤
values[i] = filterParamString(values[i]);
}
}
}
map.put(key, values);
}
return map;
}
@Override
public String getHeader(String name) {
String value = super.getHeader(filterParamString(name));
if (!StringUtils.isEmpty(value) && !TokenConstants.ACCESS_TOKEN.equals(name)) {
// 防火墙过滤
value = filterParamString(value);
}
return value;
}
/**
* request
*/
public HttpServletRequest getOrgRequest() {
return orgRequest;
}
/**
* request
*/
public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
if (request instanceof WafHttpServletRequestWrapper) {
return ((WafHttpServletRequestWrapper) request).getOrgRequest();
}
return request;
}
/**
* @Description
* @param rawValue
* @return
*/
protected String filterParamString(String rawValue) {
if (StringUtils.isEmpty(rawValue)) {
return rawValue;
}
String tmpStr = rawValue;
if (this.enableXssFilter) {
tmpStr = XSSFilterKit.stripXSS(rawValue);
}
if (this.enableSqlFilter) {
tmpStr = XSSFilterKit.stripXSS(
SQLFilterKit.stripSQL(tmpStr));
}
return tmpStr;
}
}

@ -0,0 +1,47 @@
package org.opsli.core.waf.util;
import org.opsli.common.exception.WafException;
import org.opsli.core.msg.CoreMsg;
import org.springframework.util.StringUtils;
/**
* SQL
*
* @author Parker
* @date 2020-10-09
*/
public final class SQLFilterKit {
/**
* SQL
*
* @param str
*/
public static String stripSQL(String str) {
if (StringUtils.isEmpty(str)) {
return null;
}
//去掉'|"|;|\字符
str = StringUtils.replace(str, "'", "");
str = StringUtils.replace(str, "\"", "");
str = StringUtils.replace(str, ";", "");
str = StringUtils.replace(str, "\\", "");
//转换成小写
str = str.toLowerCase();
//非法字符
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
//判断是否包含非法字符
for (String keyword : keywords) {
if (str.contains(keyword)) {
throw new WafException(CoreMsg.WAF_EXCEPTION_SQL);
}
}
return str;
}
// ====================
private SQLFilterKit(){}
}

@ -0,0 +1,81 @@
package org.opsli.core.waf.util;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Pattern;
/**
* XSS
*
* @author Parker
* @date 2020-10-09
* */
public final class XSSFilterKit {
/**
* @Description XSS
* @param value
* @return
*/
public static String stripXSS(String value) {
String rlt = null;
if (StringUtils.isNotEmpty(value)) {
// NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to
// avoid encoded attacks.
// value = ESAPI.encoder().canonicalize(value);
// Avoid null characters
rlt = value.replaceAll("", "");
// Avoid anything between script tags
Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Avoid anything in a src='...' type of expression
/*scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
rlt = scriptPattern.matcher(rlt).replaceAll("");
scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
rlt = scriptPattern.matcher(rlt).replaceAll("");*/
// Remove any lonesome </script> tag
scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Remove any lonesome <script ...> tag
scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Avoid eval(...) expressions
scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Avoid expression(...) expressions
scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Avoid javascript:... expressions
scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Avoid vbscript:... expressions
scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
rlt = scriptPattern.matcher(rlt).replaceAll("");
// Avoid onload= expressions
scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE
| Pattern.MULTILINE | Pattern.DOTALL);
rlt = scriptPattern.matcher(rlt).replaceAll("");
}
return rlt;
}
// ====================
private XSSFilterKit(){}
}
Loading…
Cancel
Save