XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
通俗来说,在新增表单里,表单内容里插入一段html或者js代码,在列表渲染时就可能执行这串js代码。这就是xss攻击。
在微服务中,我们可以很方便的去网关中处理xss攻击,即自定义过滤器,在网关进行路径分发前进行输入数据的处理
直接编写自定义过滤器,继承ZuulFilter过滤器
package com.bp.getway.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.*;
/**
* @author ZhuWeiHao
* @date 2022/1/18
* XSS过滤
*/
@Component
@Log4j2
public class XSSFilter extends ZuulFilter {
//类型 pre,在之前处理
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
//Spring的排序,越小越早加载
@Override
public int filterOrder() {
return -99;
}
//是否执行逻辑处理
@Override
public boolean shouldFilter() {
return true;
}
//过滤处理
@Override
public Object run() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String contentType = request.getContentType();
if (StringUtils.isNotBlank(contentType)) {
//表单和url提交方式
if (StringUtils.equals(contentType, "application/x-www-form-urlencoded")
|| StringUtils.equals(contentType, "application/x-www-form-urlencoded;charset=UTF-8")) {
//对象引用不允许直接对原对象进行修改
Map<String, String[]> parameterMap = new HashMap(request.getParameterMap());
if (parameterMap == null || parameterMap.isEmpty()) {
return null;
}
Map<String, List<String>> requestQueryParams = requestContext.getRequestQueryParams();
if (requestQueryParams == null) {
requestQueryParams = new HashMap<>(parameterMap.size() * 2);
}
Iterator<Map.Entry<String, String[]>> iterator = parameterMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String[]> next = iterator.next();
List<String> list = Arrays.asList(next.getValue());
for (int i = 0; i < list.size(); i++) {
list.set(i, StringEscapeUtils.escapeJavaScript(StringEscapeUtils.escapeHtml(list.get(i))));
}
String key = next.getKey();
requestQueryParams.put(key, list);
}
requestContext.setRequestQueryParams(requestQueryParams);
//json提交方式
} else if (StringUtils.equals(contentType, "application/json")
|| StringUtils.equals(contentType, "application/json;charset=UTF-8")) {
try {
InputStream in = requestContext.getRequest().getInputStream();
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
JSONObject json = JSON.parseObject(body);
Map<String, Object> map = json;
Map<String, Object> mapJson = new HashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
mapJson.put(entry.getKey(), cleanXSS(entry.getValue().toString()));
}
String newBody = JSON.toJSONString(mapJson);
byte[] reqBodyBytes = newBody.getBytes();
//注意此处的HttpServletRequestWrapper 是java.servlet包下的
//重写输入流
requestContext.setRequest(new HttpServletRequestWrapper(request) {
@Override
public ServletInputStream getInputStream() {
return new ServletInputStreamWrapper(reqBodyBytes);
}
//注意此次两个获取内容长度方法一定要重写,不然容易造成读取长度不一致的问题
@Override
public int getContentLength() {
return reqBodyBytes.length;
}
@Override
public long getContentLengthLong() {
return reqBodyBytes.length;
}
});
} catch (IOException e) {
e.printStackTrace();
log.error("xss过滤器读取参数异常");
}
}
}
return null;
}
private String cleanXSS(String value) {
if (StringUtils.isBlank(value)) {
return value;
}
value = StringEscapeUtils.escapeHtml(value);
value = StringEscapeUtils.escapeJavaScript(value);
value = value.replaceAll("\\\\", "");
return value;
}
}
运行项目,进行输入测试,xss代码被转义了,效果达到