> 文章列表 > 记录网关zuul处理跨域/XSS问题

记录网关zuul处理跨域/XSS问题

记录网关zuul处理跨域/XSS问题

一,疑问

1.之前遇到跨域问题是在NG中解决的,添加跨域请求头和域名配置。那么与网关处理跨域问题关系是什么,NG处理了,为什么还需要在网关中处理

二,前置知识

zuul概念与原理

zuul 的概念和原理 - 知乎

Zuul工作原理_zuul原理_吴声子夜歌的博客-CSDN博客

梳理几个基本概念

zuul的工作原理
1.过滤器机制
zuul的核心是一系列的filters, 其作用可以类比Servlet框架的Filter,或者AOP。
zuul把Request route到 用户处理逻辑 的过程中,这些filter参与一些过滤处理,比如Authentication,Load Shedding等

2.过滤器机制过滤器类型
Zuul大部分功能都是通过过滤器来实现的。Zuul中定义了四种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期。
(1) PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
(2) ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
(3) POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
(4) ERROR:在其他阶段发生错误时执行该过滤器

总结:通过一个个过滤器实现不同的业务逻辑,且不同过滤器类型按照顺序执行对应的业务

三,此文网关做了那几件事

1.PRE,前置需要处理的逻辑,跨域/XSS处理

2.POST,微服务处理之后记录处理时间等日志信息

具体处理逻辑

1.跨域问题重现,前端报错,如下包含了请求源Origin信息

 

 2. ZuulFilter1跨域/xss攻击代码

Component
@RefreshScope
public class TimeCostPreFilter extends ZuulFilter {public static final String START_TIME_KEY = "start_time";public static final String ZUUL_REQUEST_URL_KEY = "zuul_request_start_time";private static final Logger logger = LoggerFactory.getLogger(TimeCostPreFilter.class);@Value("${com.gateway.xss.check:true}")private Boolean xssCheck;@Value("${com.gateway.xss.url.filter:uploadFile,uploadImage}")private String urlFilter;@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}@Overridepublic int filterOrder() {return 0;}/* 判断是否要拦截的逻辑*/@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() {long startTime = System.currentTimeMillis();RequestContext currentContext = RequestContext.getCurrentContext();HttpServletRequest request = currentContext.getRequest();Enumeration<String> headerNames = request.getHeaderNames();if (headerNames != null) {while (headerNames.hasMoreElements()) {String nextElement = headerNames.nextElement();if (nextElement.equalsIgnoreCase("origin") && request.getHeader(nextElement) != null) {String str = request.getHeader(nextElement).toLowerCase();String pattern = "^(http|https)://(.*\\\\.skcloud\\\\.cn|.*\\\\.skcloud\\\\.com|.*\\\\.sk\\\\.com|localhost:?[0-9]*|api.rrx.cn|c2bt4.skcloud.com)$";Pattern r = Pattern.compile(pattern);Matcher m = r.matcher(str);if (!m.matches()) {return null;}}}}StringBuffer requestUrl = request.getRequestURL();String url = requestUrl.toString();if (xssCheck) {if (!StringUtils.isEmpty(urlFilter)) {String[] urlFilterList = urlFilter.split(",");for (String s : urlFilterList) {if (!StringUtils.isEmpty(urlFilter) && url.contains(s)) {currentContext.set(ZUUL_REQUEST_URL_KEY, url);currentContext.set(START_TIME_KEY, startTime);return null;}}}try {Map<String, String[]> map = request.getParameterMap();if (!(Objects.isNull(map) || map.isEmpty())) {for (Map.Entry<String, String[]> entry : map.entrySet()) {String[] value = entry.getValue();if (extracted(currentContext, value[0])) {return null;}}}InputStream in = request.getInputStream();String body = StreamUtils.copyToString(in, StandardCharsets.UTF_8);if (!StringUtils.isEmpty(body)) {if (extracted(currentContext, body)) {return null;}}} catch (IOException e) {e.printStackTrace();}}currentContext.set(ZUUL_REQUEST_URL_KEY, url);currentContext.set(START_TIME_KEY, startTime);return null;}private static boolean extracted(RequestContext currentContext, String body) {boolean b = checkXss(body);if (b) {currentContext.setSendZuulResponse(false);currentContext.setResponseBody("非法请求");currentContext.setResponseStatusCode(HttpStatus.BAD_REQUEST.value());return true;}return false;}public static boolean checkXss(String str) {if (StringUtils.isEmpty(str)) {return false;}boolean contains = str.contains("<");boolean contains1 = str.contains(">");boolean onclick = str.contains("onclick");return contains || contains1 || onclick;}

3. ZuulFilter2,日志记录

@Component
@RefreshScope
public class TimeCostPostFilter extends ZuulFilter {private static final String START_TIME_KE = "start_time";public static final String ZUUL_REQUEST_URL_KEY = "zuul_request_start_time";private static final Logger logger = LoggerFactory.getLogger(TimeCostPostFilter.class);@Autowiredprivate GateWayRequestTimeClient gateWayRequestTimeClient;@Overridepublic String filterType() {return FilterConstants.POST_TYPE;}@Overridepublic int filterOrder() {return 0;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() {RequestContext currentContext = RequestContext.getCurrentContext();String requestUrl = (String) currentContext.get(ZUUL_REQUEST_URL_KEY);long startTime = (long) currentContext.get(START_TIME_KE);long endTime = System.currentTimeMillis();long resultTime = endTime - startTime;int responseStatusCode = currentContext.getResponseStatusCode();gateWayRequestTimeClient.insertLog(startTime, endTime, resultTime, requestUrl, responseStatusCode);return null;}}