加入收藏 | 设为首页 | 会员中心 | 我要投稿 银川站长网 (https://www.0951zz.com/)- 云通信、基础存储、云上网络、机器学习、视觉智能!
当前位置: 首页 > 服务器 > 安全 > 正文

Gateway拦截器实现预防SQL注入 XSS攻击

发布时间:2023-08-18 11:16:31 所属栏目:安全 来源:
导读:SQL注入是常见的系统安全问题之一,用户通过特定方式向系统发送SQL脚本,可直接自定义操作系统数据库,如果系统没有对SQL注入进行拦截,那么用户甚至可以直接对数据库进行增删改查等操作。我们前面在对微服务Gateway

SQL注入是常见的系统安全问题之一,用户通过特定方式向系统发送SQL脚本,可直接自定义操作系统数据库,如果系统没有对SQL注入进行拦截,那么用户甚至可以直接对数据库进行增删改查等操作。

我们前面在对微服务Gateway进行自定义扩展时,增加了Gateway插件功能。我们会根据系统需求开发各种Gateway功能扩展插件,并且可以根据系统配置文件来启用/禁用这些插件。下面我们就将防止SQL注入/XSS攻击拦截器作为一个Gateway插件来开发和配置。

1、新增SqlInjectionFilter 过滤器和XssInjectionFilter过滤器,分别用于解析请求参数并对参数进行判断是否存在SQL注入/XSS攻脚本。此处有公共判断方法,通过配置文件来读取请求的过滤配置,因为不是多有的请求都会引发SQL注入和XSS攻击,如果无差别的全部拦截和请求,那么势必影响到系统的性能。

判断SQL注入的拦截器

复制

/**

* 防sql注入

* @author GitEgg

*/

@Log4j2

@AllArgsConstructor

public class SqlInjectionFilter implements GlobalFilter, Ordered {

......

// 当返回参数为true时,解析请求参数和返回参数

if (shouldSqlInjection(exchange))

{

MultiValueMap<String, String> queryParams = request.getQueryParams();

boolean chkRetGetParams = SqlInjectionRuleUtils.mapRequestSqlKeyWordsCheck(queryParams);

boolean chkRetJson = false;

boolean chkRetFormData = false;

HttpHeaders headers = request.getHeaders();

MediaType contentType = headers.getContentType();

long length = headers.getContentLength();

if(length > 0 && null != contentType && (contentType.includes(MediaType.APPLICATION_JSON)

||contentType.includes(MediaType.APPLICATION_JSON_UTF8))){

chkRetJson = SqlInjectionRuleUtils.jsonRequestSqlKeyWordsCheck(gatewayContext.getRequestBody());

}

if(length > 0 && null != contentType && contentType.includes(MediaType.APPLICATION_FORM_URLENCODED)){

log.debug("[RequestLogFilter](Request)FormData:{}",gatewayContext.getFormData());

chkRetFormData = SqlInjectionRuleUtils.mapRequestSqlKeyWordsCheck(gatewayContext.getFormData());

}

if (chkRetGetParams || chkRetJson || chkRetFormData)

{

return WebfluxResponseUtils.responseWrite(exchange, "参数中不允许存在sql关键字");

}

return chain.filter(exchange);

}

else {

return chain.filter(exchange);

}

}

......

}

判断XSS攻击的拦截器

复制

/**

* 防xss注入

* @author GitEgg

*/

@Log4j2

@AllArgsConstructor

public class XssInjectionFilter implements GlobalFilter, Ordered {

......

// 当返回参数为true时,记录请求参数和返回参数

if (shouldXssInjection(exchange))

{

MultiValueMap<String, String> queryParams = request.getQueryParams();

boolean chkRetGetParams = XssInjectionRuleUtils.mapRequestSqlKeyWordsCheck(queryParams);

 

boolean chkRetJson = false;

boolean chkRetFormData = false;

 

HttpHeaders headers = request.getHeaders();

MediaType contentType = headers.getContentType();

long length = headers.getContentLength();

if(length > 0 && null != contentType && (contentType.includes(MediaType.APPLICATION_JSON)

||contentType.includes(MediaType.APPLICATION_JSON_UTF8))){

chkRetJson = XssInjectionRuleUtils.jsonRequestSqlKeyWordsCheck(gatewayContext.getRequestBody());

}

if(length > 0 && null != contentType && contentType.includes(MediaType.APPLICATION_FORM_URLENCODED)){

log.debug("[RequestLogFilter](Request)FormData:{}",gatewayContext.getFormData());

chkRetFormData = XssInjectionRuleUtils.mapRequestSqlKeyWordsCheck(gatewayContext.getFormData());

}

if (chkRetGetParams || chkRetJson || chkRetFormData)

{

return WebfluxResponseUtils.responseWrite(exchange, "参数中不允许存在XSS注入关键字");

}

return chain.filter(exchange);

}

else {

return chain.filter(exchange);

}

}

......

2、新增SqlInjectionRuleUtils工具类和XssInjectionRuleUtils工具类,通过正则表达式,用于判断参数是否属于SQL注入/XSS攻击脚本。

通过正则表达式对参数进行是否有SQL注入风险的判断

复制

/**

* 防sql注入工具类

* @author GitEgg

*/

@Slf4j

public class SqlInjectionRuleUtils {

/**

* SQL的正则表达式

*/

private static String badStrReg = "\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";

/**

* sql注入校验 map

*

* @param map

* @return

*/

public static boolean mapRequestSqlKeyWordsCheck(MultiValueMap<String, String> map) {

//对post请求参数值进行sql注入检验

return map.entrySet().stream().parallel().anyMatch(entry -> {

//这里需要将参数转换为小写来处理

String lowerValue = Optional.ofNullable(entry.getValue())

.map(Object::toString)

.map(String::toLowerCase)

.orElse("");

if (sqlPattern.matcher(lowerValue).find()) {

log.error("参数[{}]中包含不允许sql的关键词", lowerValue);

return true;

}

return false;

});

}

/**

* sql注入校验 json

*

* @param value

* @return

*/

public static boolean jsonRequestSqlKeyWordsCheck(String value) {

if (JSONUtil.isJsonObj(value)) {

JSONObject json = JSONUtil.parseObj(value);

Map<String, Object> map = json;

//对post请求参数值进行sql注入检验

return map.entrySet().stream().parallel().anyMatch(entry -> {

//这里需要将参数转换为小写来处理

String lowerValue = Optional.ofNullable(entry.getValue())

.map(Object::toString)

.map(String::toLowerCase)

.orElse("");

if (sqlPattern.matcher(lowerValue).find()) {

log.error("参数[{}]中包含不允许sql的关键词", lowerValue);

return true;

}

return false;

});

} else {

JSONArray json = JSONUtil.parseArray(value);

List<Object> list = json;

//对post请求参数值进行sql注入检验

return list.stream().parallel().anyMatch(obj -> {

//这里需要将参数转换为小写来处理

String lowerValue = Optional.ofNullable(obj)

.map(Object::toString)

.map(String::toLowerCase)

.orElse("");

if (sqlPattern.matcher(lowerValue).find()) {

log.error("参数[{}]中包含不允许sql的关键词", lowerValue);

return true;

}

return false;

});

}

}

}

通过正则表达式对参数进行是否有XSS攻击风险的判断

复制

/**

* XSS注入过滤工具类

* @author GitEgg

*/

public class XssInjectionRuleUtils {

private static final Pattern[] PATTERNS = {

// Avoid anything in a <script> type of expression

Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),

// Avoid anything in a src='...' type of expression

Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),

Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),

// Remove any lonesome </script> tag

Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),

// Avoid anything in a <iframe> type of expression

Pattern.compile("<iframe>(.*?)</iframe>", Pattern.CASE_INSENSITIVE),

// Remove any lonesome <script ...> tag

Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),

// Remove any lonesome <img ...> tag

Pattern.compile("<img(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),

// Avoid eval(...) expressions

Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),

// Avoid expression(...) expressions

Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),

// Avoid javascript:... expressions

Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),

// Avoid vbscript:... expressions

Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),

// Avoid onload= expressions

Pattern.compile("on(load|error|mouseover|submit|reset|focus|click)(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)

};

public static String stripXSS(String value) {

if (StringUtils.isEmpty(value)) {

return value;

}

for (Pattern scriptPattern : PATTERNS) {

value = scriptPattern.matcher(value).replaceAll("");

}

return value;

}

public static boolean hasStripXSS(String value) {

if (!StringUtils.isEmpty(value)) {

for (Pattern scriptPattern : PATTERNS) {

if (scriptPattern.matcher(value).find() == true)

{

return true;

}

}

}

return false;

}

/**

* xss注入校验 map

*

* @param map

* @return

*/

public static boolean mapRequestSqlKeyWordsCheck(MultiValueMap<String, String> map) {

//对post请求参数值进行sql注入检验

return map.entrySet().stream().parallel().anyMatch(entry -> {

//这里需要将参数转换为小写来处理

String lowerValue = Optional.ofNullable(entry.getValue())

.map(Object::toString)

.map(String::toLowerCase)

.orElse("");

if (hasStripXSS(lowerValue)) {

return true;

}

return false;

});

}

/**

* xss注入校验 json

*

* @param value

* @return

*/

public static boolean jsonRequestSqlKeyWordsCheck(String value) {

if (JSONUtil.isJsonObj(value)) {

JSONObject json = JSONUtil.parseObj(value);

Map<String, Object> map = json;

//对post请求参数值进行sql注入检验

return map.entrySet().stream().parallel().anyMatch(entry -> {

//这里需要将参数转换为小写来处理

String lowerValue = Optional.ofNullable(entry.getValue())

.map(Object::toString)

.map(String::toLowerCase)

.orElse("");

if (hasStripXSS(lowerValue)) {

return true;

}

return false;

});

} else {

JSONArray json = JSONUtil.parseArray(value);

List<Object> list = json;

//对post请求参数值进行sql注入检验

return list.stream().parallel().anyMatch(obj -> {

//这里需要将参数转换为小写来处理

String lowerValue = Optional.ofNullable(obj)

.map(Object::toString)

.map(String::toLowerCase)

.orElse("");

if (hasStripXSS(lowerValue)) {

return true;

}

return false;

});

}

}

}

在GatewayRequestContextFilter 中新增判断那些请求需要解析参数。因为出于性能等方面的考虑,网关并不是对所有的参数都进行解析,只有在需要记录日志、防止SQL注入/XSS攻击时才会进行解析。

(编辑:银川站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!