java防止html脚本注入

html脚本注入就是跨站脚本攻击(XSS),指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。

有如下案例:

在前端输入一些内容,提交到服务器后直接原样返回,然后再append到一个div中显示:

<form id="f1">
    Name:<input type="text" name="name"/>
    <input type="button" value="submit"/>
</form>
<div id="content"></div>
<script src="js/jquery-1.12.4.min.js"></script>
<script>
    $(function(){
        $(':button').on('click', function(){
            var param = $('#f1').serialize();
            $.ajax({
                url : 'add',
                type : 'post',
                data : param,
                success : function(result){
                    console.log(result);
                    $('#content').append(result + '<br>');
                }
            });
        });
    })
</script>

 

@RestController
public class TestController {

    @PostMapping("/add")
    public String add(String name){
        System.out.println(name);
        return name;
    }
}

如果在运行后输入一串html脚本代码,运行如下:

在控制台输出内容:

<a href="#">hello<a>

可以看到,如果输入一个html脚本代码,那么打印的就可能不再是原本的那串字符,而是经过解析后呈现的一个标签。

这里就来解决html脚本注入问题:

这里的解决思路就是定义一个拦截器,拦截所有请求,因为请求的所有表单数据都存放在HttpServletRequest对象中,所以只需要拿到这个对象并对原有的方法进行增强即可。

导包:

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-text -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>1.6</version>
    </dependency>
</dependencies>

自定义一个请求包裹器,继承HttpServletRequestWrapper类,HttpServletRequestWrapper这个类就是一个请求包裹器,用于覆盖request对象中的方法,对原有的方法进行增强,这里就是典型的装饰者模式。在代码中,可以使用StringEscapeUtils.escapeHtml4(),这个方法是对字符串进行格式化,如“<,>,*,#”等字符串会格式成“<”,等。

public class XssRequestWrapper extends HttpServletRequestWrapper {

    public XssRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        return StringEscapeUtils.escapeHtml4(value);
    }

    @Override
    public String getParameter(String name) {
        //获取页面数据
        String value = super.getParameter(name);
        //进行字符转义
        System.out.println("转义后的字符:" + StringEscapeUtils.escapeHtml4(value));
        return StringEscapeUtils.escapeHtml4(value);
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if(values != null){
            String[] escValues = new String[values.length];
            for (int i=0; i<values.length; i++) {
                escValues[i] = StringEscapeUtils.escapeHtml4(values[i]);
            }
            return escValues;
        }
        return super.getParameterValues(name);
    }
}

定义一个过滤器,拦截所有请求:

@WebFilter(urlPatterns = "/*")
public class XssFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        //实例化自定义的RequestWrapper对象
        XssRequestWrapper requestWrapper = new XssRequestWrapper(request);
        //放行,HttpServletRequest最终也是实现了ServletRequest,所以放行可以传requestWrapper对象
        filterChain.doFilter(requestWrapper, servletResponse);
    }
}

运行结果:

控制台输出:

&lt;a href=&quot;#&quot;&gt;hello&lt;a&gt;

 

posted @ 2020-05-27 20:04  张财华  阅读(2478)  评论(0编辑  收藏  举报