First, XSS attack

XSS attack usually refers to the use of loopholes left in the development of web pages, through clever methods to inject malicious instruction code to the web page, users load and execute the malicious web page program made by the attackers. These malicious web programs are usually JavaScript, but can actually include Java, VBScript, ActiveX, Flash, or even plain HTML. After a successful attack, the attacker may gain various contents including but not limited to higher permissions (such as performing some operations), private web content, sessions and cookies.

Import the dependency library

Because the Hutool toolkit comes with XSS escaped utility classes, we import Hutool and define data escape capabilities using the request wrapper classes provided by the Servlet specification.

<dependency>
	<groupId>cn.hutool</groupId>
	<artifactId>hutool-all</artifactId>
	<version>5.4.0</version>
</dependency>
Copy the code

Request to define the wrapper class

The HttpservletRequest that we encounter when writing Web projects is actually an interface. If we want to redefine the request class, extending this interface is the last thing we should do. Because there are so many abstract methods in the HttpservletRequest interface, implementing them one by one would be too time-consuming. So we should pick an easier way to customize the request class. That is inherited HttpServletRequestwrapper parent class. JavaEE is only a standard, and its implementation is done by various application server vendors. For example, when Tomcat implements the Servlet specification, it customizes the HttpservletRequest interface implementation class. JavaEE specification also defines HttpServletRequestwrapper, this class is request wrapper classes in a class, use the decorator pattern. Have to say here use design pattern is really very good, no matter how each application server vendors to achieve it interface, the user wants to custom request, only needs to inherit HttpServletRequestwrapper, corresponding to cover a method, The request is then passed into the request wrapper class, and the decorator pattern replaces one of the corresponding methods in the request object. The user’s code is completely decoupled from the server vendor’s code, and we don’t care how the HttpServletRequest interface is implemented. With the help of wrapper classes, we can modify the methods in the request at will.


public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

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

    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if(! StrUtil.hasEmpty(value)) { value = HtmlUtil.filter(value); }return value;
    }

    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if(values ! =null) {
            for (int i = 0; i < values.length; i++) {
                String value = values[i];
                if (!StrUtil.hasEmpty(value)) {
                    value = HtmlUtil.filter(value);
                }
                values[i] = value;
            }
        }
        return values;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> parameters = super.getParameterMap();
        Map<String, String[]> map = new LinkedHashMap<>();
        if(parameters ! =null) {
            for (String key : parameters.keySet()) {
                String[] values = parameters.get(key);
                for (int i = 0; i < values.length; i++) {
                    String value = values[i];
                    if (!StrUtil.hasEmpty(value)) {
                        value = HtmlUtil.filter(value);
                    }
                    values[i] = value;
                }
                map.put(key, values);
            }
        }
        return map;
    }

    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if(! StrUtil.hasEmpty(value)) { value = HtmlUtil.filter(value); }return value;
    }

    @Override
    public ServletInputStream getInputStream(a) throws IOException {
        InputStream in = super.getInputStream();
        StringBuffer body = new StringBuffer();
        InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
        BufferedReader buffer = new BufferedReader(reader);
        String line = buffer.readLine();
        while(line ! =null) {
            body.append(line);
            line = buffer.readLine();
        }
        buffer.close();
        reader.close();
        in.close();

        Map<String, Object> map = JSONUtil.parseObj(body.toString());
        Map<String, Object> resultMap = new HashMap(map.size());
        for (String key : map.keySet()) {
            Object val = map.get(key);
            if (map.get(key) instanceof String) {
                resultMap.put(key, HtmlUtil.filter(val.toString()));
            } else {
                resultMap.put(key, val);
            }
        }
        String str = JSONUtil.toJsonStr(resultMap);
        final ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes());
        return new ServletInputStream() {
            @Override
            public int read(a) throws IOException {
                return bain.read();
            }

            @Override
            public boolean isFinished(a) {
                return false;
            }

            @Override
            public boolean isReady(a) {
                return false;
            }

            @Override
            public void setReadListener(ReadListener listener) {}}; }}Copy the code

Create a filter that passes the request object to the wrapper class

To make the wrapper class we just defined work, we also create the xssFilter filter in com.example.emos.wx.config.xss. The filter intercepts all requests and passes them to the wrapper class, which overrides all request parameter methods and the user gets the data from the request, all escaped.

package com.example.emos.wx.config.xss;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

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

    public void init(FilterConfig config) throws ServletException {}public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
                (HttpServletRequest) request);
        chain.doFilter(xssRequest, response);
    }

    @Override
    public void destroy(a) {}}Copy the code

5. Add annotations to the main class

Annotate the SpringBoot main class with @ServletComponentScan.

Test intercepting XSS script

I pass a <script>alert(" XSS scripting attack ")</script> script to see if the HTML tag in the result can be filtered outCopy the code

Test results:As shown above, the label in the argument is filtered out and the character removed from the label is returned!