存储XSS跨站脚本攻击过滤解决方案

和自甴很熟 提交于 2019-11-30 09:37:54

漏洞描述:本页面存在跨站脚本攻击。跨站脚本漏洞,即XSS,通常用Javascript语言描述,它允许攻击者发送恶意代码给另一个用户。因为浏览器无法识别脚本是否可信,跨站漏洞脚本便运行并让攻击者获取其他用户的cookie或session。

加固建议:

总体修复方式:验证所有输入数据,有效检测攻击;对所有输出数据进行适当的编码,以防止任何已成功注入的脚本在浏览器端运行。具体如下 :

输入验证:某个数据被接受为可被显示或存储之前,使用标准输入验证机制,验证所有输入数据的长度、类型、语法以及业务规则。

输出编码:数据输出前,确保用户提交的数据已被正确进行entity编码,建议对所有字符进行编码而不仅局限于某个子集。

注意黑名单验证方式的局限性:仅仅查找或替换一些字符(如"<" ">"或类似"script"的关键字),很容易被XSS变种攻击绕过验证机制。

警惕规范化错误:验证输入之前,必须进行解码及规范化以符合应用程序当前的内部表示方法。请确定应用程序对同一输入不做两次解码。对客户端提交的数据进行过滤,一般建议过滤掉双引号(”)、尖括号(<、>)等特殊字符,或者对客户端提交的数据中包含的特殊字符进行实体转换,比如将双引号(”)转换成其实体形式",<对应的实体形式是<,<对应的实体形式是>以下为需过滤的常见字符:

[1] |(竖线符号)

[2] & (& 符号)

[3];(分号)

[4] $(美元符号)

[5] %(百分比符号)

[6] @(at 符号)

[7] '(单引号)

[8] "(引号)

[9] \'(反斜杠转义单引号)

[10] \"(反斜杠转义引号)

[11] <>(尖括号)

[12] ()(括号)

[13] +(加号)

[14] CR(回车符,ASCII 0x0d)

[15] LF(换行,ASCII 0x0a)

[16] ,(逗号)

[17] \(反斜杠)

在请求返回页面关键字符进行转义;

[1] “(双引号):&quot

[2] ’ (单引号):&apos

[3] &(&符号):&amp

[4] <(左尖括号):&lt

[5] >(右尖括号):&gt

在不影响应用的前提下,建议将cookie标记为httpOnly,同时禁用TRACE方法。

以上是绿盟给出的扫描结果和建议。

网上找了很多,大多只是过滤了普通请求参数的,并不包括json格式的,这也是我开始过滤不了的原因。原理挺简单的,解决XSS攻击,可以通过后端对输入的数据做过滤或者转义,使XSS攻击代码失效。为大家提供一个,避免走弯路

XssAndSqlHttpServletRequestWrapper.java

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * 防止XSS攻击
 */
public class XssAndSqlHttpServletRequestWrapper extends HttpServletRequestWrapper {
 private HttpServletRequest request;
 public XssAndSqlHttpServletRequestWrapper(HttpServletRequest request) {
 super(request);
 this.request = request;
 }
 @Override
 public String getParameter(String name) {
 String value = request.getParameter(name);
 if (!StringUtils.isEmpty(value)) {
 value = StringEscapeUtils.escapeHtml4(value);
 }
 return value;
 }
 @Override
 public String[] getParameterValues(String name) {
 String[] parameterValues = super.getParameterValues(name);
 if (parameterValues == null) {
 return null;
 }
 for (int i = 0; i < parameterValues.length; i++) {
 String value = parameterValues[i];
 parameterValues[i] = StringEscapeUtils.escapeHtml4(value);
 }
 return parameterValues;
 }
}

这里重写了两个方法:getParameter和getParameterValues,getParameter方法是直接通过request获得querystring类型的入参调用的方法。如果是通过springMVC注解类型来获得参数的话,走的是getParameterValues的方法。大家可以通过打印一个输出来验证一下。

StringEscapeUtils.escapeHtml4这个方法来自Apache的工具类,maven坐标如下:

<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-text</artifactId>
 <version>1.4</version>
</dependency>

XssFilter.java

过滤的代码写完了,下面就是在一个filter中应用该代码。

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;


@WebFilter
@Component
public class XssFilter implements Filter {
 @Override
 public void init(FilterConfig filterConfig) throws ServletException {
 }
 @Override
 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
 throws IOException, ServletException {
 HttpServletRequest req = (HttpServletRequest) request;
 XssAndSqlHttpServletRequestWrapper xssRequestWrapper = new XssAndSqlHttpServletRequestWrapper(req);
 chain.doFilter(xssRequestWrapper, response);
 }
 @Override
 public void destroy() {
 }
 /**
 * 过滤json类型的
 * @param builder
 * @return
 */
 @Bean
 @Primary
 public ObjectMapper xssObjectMapper(Jackson2ObjectMapperBuilder builder) {
 //解析器
 ObjectMapper objectMapper = builder.createXmlMapper(false).build();
 //注册xss解析器
 SimpleModule xssModule = new SimpleModule("XssStringJsonSerializer");
 xssModule.addSerializer(new XssStringJsonSerializer());
 objectMapper.registerModule(xssModule);
 //返回
 return objectMapper;
 }
}

过滤表单类型的代码已经完成(xssObjectMapper这个是后面过滤json类型才用到的)。下面来实现过滤json类型的代码:

XssStringJsonSerializer.java

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.apache.commons.text.StringEscapeUtils;
import java.io.IOException;
public class XssStringJsonSerializer extends JsonSerializer<String> {
 @Override
 public Class<String> handledType() {
 return String.class;
 }
 @Override
 public void serialize(String value, JsonGenerator jsonGenerator,
 SerializerProvider serializerProvider) throws IOException {
 if (value != null) {
 String encodedValue = StringEscapeUtils.escapeHtml4(value);
 jsonGenerator.writeString(encodedValue);
 }
 }
}

这里是通过修改SpringMVC的json序列化来达到过滤xss的目的的。其实也可以通过第一种方法,重写getInputStream方法来实现,这里我就不做演示了(通过json类型传参会走getInputStream方法,通过重写该方法打印输出可以证明)。

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!