纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

springboot防止XSS攻击 springboot项目怎样防止XSS攻击

细肉云吞   2021-06-23 我要评论
想了解springboot项目怎样防止XSS攻击的相关内容吗细肉云吞在本文为您仔细讲解springboot防止XSS攻击的相关知识和一些Code实例欢迎阅读和指正我们先划重点:springboot,防止攻击,springboot,xss攻击下面大家一起来学习吧。

1. 什么是XSS攻击?

    XSS攻击全称跨站脚本攻击是一种在web应用中的计算机安全漏洞它允许恶意web用户将代码植入到提供给其它用户使用的页面中。也就是作恶的用户通过表单提交一些前端代码如果不做处理的话这些前端代码将会在展示的时候被浏览器执行。

2. 如何防范?

有两种方式一种是一些特殊字符转义另一种是去除一些危险html元素。本文通过JSOUP库实现第二种方式。

现在问题是在什么时候对XSS攻击的字符串进行处理呢?这就涉及到spring mvc的Controller中的method params什么时候注入的问题。下面对方法参数注入的原理进行简单说明。

2.1 什么时候注入请求参数

常见的控制器方法有下面几种分别是通过GET获取请求参数POST获取json或者form表单的参数

        /**
         * 通过url的path获取请求参数
         */
        @ResponseBody
        @GetMapping("/xssByGetUsingPath/{content}")
        public String testGetUsingPath(@PathVariable(name = "content") String content) {
            return content;
        }       


         /**
         * 通过url的query params获取请求数据. 方法使用简单类型进行接收
         */
        @ResponseBody
        @GetMapping("/xssByGetUsingSimple")
        public String testUsingSimple(@RequestParam(name = "content") String content) {
            return content;
        }

        /**
         * 通过url的query params获取请求数据. 方法使用model进行接收
         */
        @ResponseBody
        @GetMapping("/xssByGetUsingModel")
        public String testGetUsingModel(BaseTest.Paper paper) {
            return paper.getContent();
        }

        /**
         * 通过 form 表单的方式获取数据. 方法使用简单类型进行接收
         */
        @ResponseBody
        @PostMapping("/xssByFormPostUsingSimple")
        public String testFormPostUsingSimple(@RequestParam(name = "content") String content) {
            return content;
        }

        /**
         * 通过 form 表单的方式获取数据. 方法使用model进行参数接收
         */
        @ResponseBody
        @PostMapping("/xssByFormPostUsingModel")
        public String testFormPostUsingModel(BaseTest.Paper paper) {
            return paper.getContent();
        }

        /**
         * 通过 request body 发送 json数据
         */
        @ResponseBody
        @PostMapping("/xssByPostJsonBody")
        public String testPostJsonBody(@RequestBody BaseTest.Paper paper) {
            return paper.getContent();
        }

大家都知道在spring mvc中处理请求的入口在 DispatcherServlet 类中其中 doDispatch() 方法完成所有核心功能。在该主流程中HandlerAdapter 将会对HTTP请求进行 Controller 的方法调用以及对请求结果进行转换并封装为DispatcherServlet 类需要的 ModelAndView 。在这里由于使用注解的方式进行 Controller 定义所以 HandlerAdapter 的实现类为 RequestMappingHandlerAdapter 。RequestMappingHandlerAdapter 类的 handle() 方法中委托给 HandlerMethodArgumentResolver 对每个 Controller 的 方法的每个参数进行解析反射调用 Controller 的 方法后再 委托 HandlerMethodReturnValueHandler 对反射调用的返回值进行处理。

至此本文的主角出现了也就是 HandlerMethodArgumentResolver 。我们看下有关于本文的HandlerMethodArgumentResolver 类继承关系。

上面的常见controller定义方法的 参数解析(注意这里是说方法那里的参数解析) 对应 HandlerMethodArgumentResolver  的关系如下图:

现在我们已经知道了他们都由什么样 HandlerMethodArgumentResolver  解析方法参数我们继续分析他们之前的共同点并得到在哪里对http传过来的数据进行XSS处理。

RequestResponseBodyMethodProcessor 是一个对request body的JSON数据反序列化的处理器在 resolveArgument() 方法中将会获取合适的 org.springframework.http.converter.HttpMessageConverter  类对string数据进行反序列化处理。springboot 在初始化的时候已经默认注册了 jackson 的 MappingJackson2HttpMessageConverter 并使用它对 JSON 数据进行反序列化操作。在 jackson 里面JsonDeserializer 类 用于json数据的property的反序列化因此我们可以通过扩展 JsonDeserializer 并在里面处理XSS即可。

对于  PathVariableMethodArgumentResolver、 RequestParamMethodArgumentResolver、 ServletModelAttributeMethodProcessor 在 resolveArgument() 方法中他们对需要对请求参数调用 DataBinder 类 对获取到的参数类型转换和数据绑定。对于类型转换的过程他们会使用 org.springframework.core.convert.converter.Converter  进行转换。同样在SPRINGBOOT初始化的过程也注册了很多个默认的转换器我们可以注册一个自定义转换器用于对数据进行xss处理。

3. 具体处理细节

抽象XSSCleaner用于对string进行XSS处理

public interface XssCleaner {

    /**
     * 清理 html, 防止XSS
	 *
     * @param html html
     * @return 清理后的数据
     */
    String clean(String html);

}

使用JSOUP做HTML节点的白名单处理

public class DefaultXssCleaner implements XssCleaner {

    public static final HtmlWhitelist WHITE_LIST = new HtmlWhitelist();

    @Override
    public String clean(String html) {
        if (StringUtils.hasText(html)) {
            return Jsoup.clean(html, WHITE_LIST);
        }
        return html;
    }

    private static class HtmlWhitelist extends Whitelist {

        public HtmlWhitelist() {
            //定义标签和属性的白名单

            addTags("a", "b", "blockquote", "br", "caption", "cite", "code", "col", "colgroup", "dd", "div", "span", "embed", "object", "dl", "dt",
                    "em", "h1", "h2", "h3", "h4", "h5", "h6", "i", "img", "li", "ol", "p", "pre", "q", "small",
                    "strike", "strong", "sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "u", "ul");

            addAttributes("a", "href", "title", "target");
            addAttributes("blockquote", "cite");
            addAttributes("col", "span");
            addAttributes("colgroup", "span");
            addAttributes("img", "align", "alt", "src", "title");
            addAttributes("ol", "start");
            addAttributes("q", "cite");
            addAttributes("table", "summary");
            addAttributes("td", "abbr", "axis", "colspan", "rowspan", "width");
            addAttributes("th", "abbr", "axis", "colspan", "rowspan", "scope", "width");
            addAttributes("video", "src", "autoplay", "controls", "loop", "muted", "poster", "preload");
            addAttributes("object", "width", "height", "classid", "codebase");
            addAttributes("param", "name", "value");
            addAttributes("embed", "src", "quality", "width", "height", "allowFullScreen", "allowScriptAccess", "flashvars", "name", "type", "pluginspage");

            addAttributes(":all", "class", "style", "height", "width", "type", "id", "name");

            addProtocols("blockquote", "cite", "http", "https");
            addProtocols("cite", "cite", "http", "https");
            addProtocols("q", "cite", "http", "https");

        }

        @Override
        protected boolean isSafeAttribute(String tagName, Element el, Attribute attr) {
            //不允许 javascript 开头的 src 和 href
            if ("src".equalsIgnoreCase(attr.getKey()) || "href".equalsIgnoreCase(attr.getKey())) {
                String value = attr.getValue();
                if (StringUtils.hasText(value) && value.toLowerCase().startsWith("javascript")) {
                    return false;
                }
            }

            //允许 base64 的图片内容
            if ("img".equals(tagName) && "src".equals(attr.getKey()) && attr.getValue().startsWith("data:;base64")) {
                return true;
            }

            return super.isSafeAttribute(tagName, el, attr);
        }
    }
}

新增一个jackson的JsonDeserializer 

/**
 * jackson的反序列化时的html xss过滤器
 */
public class JacksonXssCleanJsonDeserializer extends JsonDeserializer<String> {

    private final static Logger LOGGER = LoggerFactory.getLogger(JacksonXssCleanJsonDeserializer.class);

    private final XssCleaner xssCleaner;

    public JacksonXssCleanJsonDeserializer(XssCleaner xssCleaner) {
        this.xssCleaner = xssCleaner;
    }

    @Override
    public Class<?> handledType() {
        return String.class;
    }

    @Override
    public String deserialize(JsonParser p, DeserializationContext context) throws IOException, JsonProcessingException {
        // XSS clean
        String text = p.getValueAsString();
        if (StringUtils.hasText(text) && XssCleanMarker.shouldClean()) {
            String cleanText = xssCleaner.clean(text);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Json property value: [{}] cleaned up by JacksonXssCleanJsonDeserializer, current value is:{}.", text, cleanText);
            }
            return cleanText;
        }
        return text;
    }
}

新增 Converter 

/**
 * 对请求数据过滤xss
 */
public class XssCleanConverter implements Converter<String, String> {

    private final Logger LOGGER = LoggerFactory.getLogger(XssCleanConverter.class);

    private XssCleaner xssCleaner;

    public XssCleanConverter(XssCleaner xssCleaner) {
        this.xssCleaner = xssCleaner;
    }

    @Override
    public String convert(String text) {
        if (StringUtils.hasText(text) && XssCleanMarker.shouldClean()) {
            String cleanText = xssCleaner.clean(text);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("request param [{}] cleaned up by XssCleanConverter, current value is:{}.", text, cleanText);
            }
            return cleanText;
        }
        return text;
    }
}

对 JsonDeserializer  和 Converter 进行注册

@Configuration
@ConditionalOnProperty(value = XSS_PROPERTIES_ENABLED, havingValue = "true", matchIfMissing = true)
@ConditionalOnWebApplication
@EnableConfigurationProperties({XssProperties.class})
public class WebXssConfiguration implements WebMvcConfigurer {

    private XssProperties properties;

    public WebXssConfiguration(XssProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConditionalOnMissingBean
    public XssCleaner xssCleaner() {
        return new DefaultXssCleaner();
    }

    @Bean
    @ConditionalOnClass(value = {ObjectMapper.class, Jackson2ObjectMapperBuilder.class})
    public Jackson2ObjectMapperBuilderCustomizer jacksonXssCleanJsonDeserializerCustomer(XssCleaner xssCleaner) {
        return builder -> builder.deserializers(new JacksonXssCleanJsonDeserializer(xssCleaner));
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        XssCleaner xssCleaner = xssCleaner();
        registry.addConverter(new XssCleanConverter(xssCleaner));
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        XssCleanMarkerHandlerInterceptor handlerInterceptor = new XssCleanMarkerHandlerInterceptor(properties);
        registry.addInterceptor(handlerInterceptor);
    }
}

上面是XSS处理的核心代码。处理XSS处理还进行了一些扩展比如 http path 路径的过滤 和 一些使能控制。

完整的代码可以参考仓库:仓库地址


相关文章

猜您喜欢

  • 压缩Redis字符串对象 压缩Redis里的字符串大对象操作

    想了解压缩Redis里的字符串大对象操作的相关内容吗持盾的紫眸在本文为您仔细讲解压缩Redis字符串对象的相关知识和一些Code实例欢迎阅读和指正我们先划重点:压缩Redis对象,压缩字符串大对象下面大家一起来学习吧。..
  • OpenCV直线检测并消除 OpenCV实现直线检测并消除

    想了解OpenCV实现直线检测并消除的相关内容吗Leonwenbin在本文为您仔细讲解OpenCV直线检测并消除的相关知识和一些Code实例欢迎阅读和指正我们先划重点:OpenCV直线检测,OpenCV直线消除,OpenCV检测消除下面大家一起来学习吧。..

网友评论

Copyright 2020 www.Shellfishsoft.com 【贝软下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式