How to prevent XSS attacks in Servlet based web applications

Posted by peterj on Sun, 02 Jan 2022 07:31:33 +0100

Servlets use jsp as the view template. jsp itself has XSS vulnerabilities. If the Web application is based on Servlet Technology and uses jsp as the view template without introducing any security framework, your application has XSS vulnerabilities.

This paper mainly introduces how to prevent XSS attacks in web applications based on Servlet.

1. Types of XSS vulnerabilities

  • Reflective XSS: < non persistent > attackers make attack links in advance. They need to deceive users to click the links to trigger XSS code (there are no such pages and contents in the server). Generally, they are easy to appear on the search page.

  • Stored XSS: < persistence > codes are stored in the server. For example, add codes in personal information or published articles. If the filtering is not strict or not strict, these codes will be stored in the server. Code execution will be triggered whenever a user visits the page. This XSS is very dangerous and easy to cause worms, A large number of cookie s are stolen (although there is also a DOM type XSS, it is also included in the storage type XSS).

  • DOM type XSS: a vulnerability based on document object model (DOM). DOM is an interface independent of platform and programming language. It allows programs or scripts to dynamically access and update document content, structure and style. The processed results can become a part of the display page. There are many objects in DOM, some of which can be manipulated by users, such as uRI, location, refelTer, etc. The client script program can dynamically check and modify the page content through the dom. It does not rely on submitting data to the server, but the data in the DOM obtained from the client is executed locally. If the data in the DOM is not strictly confirmed, a DOM XSS vulnerability will be generated.

2. XSS generation process

Take the following example:
There is a jsp page in the website, which contains a form for users to submit some content:

<%@ page pageEncoding="utf-8" %>
<html lang="zh">
<head>
    <meta charset="utf-8">
    <title>XSS Vulnerability testing</title>
</head>
<body>
<h2>XSS Vulnerability testing</h2>
<form action="${pageContext.request.contextPath}/submit" method="post">
    <label>
        <input name="text">
    </label>
    <input type="submit" name="Submit"/>
</form>
</body>
</html>

After clicking submit, the user will enter the / submit process and forward the parameters and requests to / show JSP page

@WebServlet(urlPatterns = "/submit")
public class SubmitServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        final String text = req.getParameter("text");
        req.setAttribute("text",text);
        req.getRequestDispatcher("/show.jsp").forward(req,resp);
    }

}

show.jsp will render the data to the page:

<%@ page pageEncoding="UTF-8" %>
<html>
<head>
    <title>show</title>
</head>
<body>
    <h2>Will show alert</h2>
    <div>${requestScope.text}</div>
</body>
</html>

What happens if we type < script > alert ('123 ') < / script > in the form?

Click submit:

See the execution result of < script > alert ('123 ') < / script > pop up on the page!
The data submitted by the user has been executed! This is the process of XSS generation. Assuming that the site is a cookie based session mechanism, and the data submitted by the user is the js code to extract the cookie of the site, then the user's reply will be taken by others and you can enter your account! The security caused by this vulnerability to users is extremely serious!

3. Prevent XSS attacks by filtering forms submitted by users

For stored XSS, you can block it by filtering the forms submitted by users.
The general practice is to escape the tag of html code for the data submitted by the user, for example:

  • Escape < to & lt;
  • Escape > to & gt;
  • Escape "as & quot;
  • etc.
    Servlet based applications can use Filter to escape:

XSSProtectFilter.java

@WebFilter("/*")
public class XSSProtectFilter extends BaseWebFilter {
    @Override
    protected void doInternalFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        final XSSProtectRequestWrapper xssProtectRequestWrapper = new XSSProtectRequestWrapper(request);
        response.addHeader("X-XSS-Protection","1;mode=block");
        chain.doFilter(xssProtectRequestWrapper,response);
    }
}

XSSProtectRequestWrapper.java

public class XSSProtectRequestWrapper extends HttpServletRequestWrapper {

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

    @Override
    public String getParameter(String name) {
        String parameter = super.getParameter(name);
        return encodeParameter(parameter);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        final Map<String, String[]> parameterMap = super.getParameterMap();
        if(parameterMap == null)
            return null;
        final HashMap<String, String[]> encodedParameterMap = new HashMap<>();
        final Set<String> keys = parameterMap.keySet();
        for (String key : keys) {
            final String[] params = parameterMap.get(key);
            final String[] encodeParams = encodeParameters(params);
            encodedParameterMap.put(key,encodeParams);
        }
        return encodedParameterMap;
    }

    @Override
    public String[] getParameterValues(String name) {
        final String[] parameterValues = super.getParameterValues(name);
        return encodeParameters(parameterValues);
    }

    private String[] encodeParameters(String[] parameters) {
        if(parameters == null || parameters.length == 0)
            return parameters;
        final String[] encodedParams = new String[parameters.length];
        int i = 0;
        for (String parameter : parameters) {
            final String encodedParam = encodeParameter(parameter);
            encodedParams[i++] = encodedParam;
        }
        return encodedParams;
    }

    private String encodeParameter(String parameter) {
        if (parameter == null)
            return null;
        parameter = parameter.replace("&", "&amp;");
        parameter = parameter.replace(" ", "&nbsp;");
        parameter = parameter.replace("<", "&lt;");
        parameter = parameter.replace(">", "&gt;");
        parameter = parameter.replace("\"", "&quot;");
        parameter = parameter.replace("'", "&apos;");
        return parameter;
    }
}

Submit the form at this time:

Click submit:

It is found that the alert pop-up layer disappears and the js code is displayed on the page,
View html source code:

js code was escaped, so xss disappeared.

Topics: Java security