Skip to main content

    XSS prevention for Java + JSP

    This is a cross-site scripting (XSS) prevention cheat sheet by Semgrep, Inc. It contains code patterns of potential XSS in an application. Instead of scrutinizing code for exploitable vulnerabilities, the recommendations in this cheat sheet pave a safe road for developers that mitigate the possibility of XSS in your code. By following these recommendations, you can be reasonably sure your code is free of XSS.

    Mitigation Summary

    JSPs are fraught with peril. HTML escaping in JSP templates requires escaping all data that is rendered onto the page. Worse, business logic can be embedded into JSPs with scriptlets. This is easy to forget or abuse and can easily create XSS vulnerabilities. The default option should be the safe option: Consider using a view or template engine that escapes by default, such as JSF or Velocity. If you cannot migrate to another framework, use a custom EL resolver that applies escaping by default in JSPs, such as https://docs.oracle.com/javaee/6/api/javax/el/ELResolver.html, otherwise you MUST ensure all data is escaped. Do not use scriptlets.

    If you are developing a REST API, consider using JAX-RS instead of writing directly to HttpServletResponse. This is easier to review, maintain, and audit for issues. And as always, develop a secure coding policy and use a security checker to enforce it.

    Semgrep ruleset for this cheatsheet: p/minusworld.java-httpservlet-jsp-xss

    Check your project using Semgrep

    The following command runs an optimized set of rules for your project:

    semgrep --config p/default

    1. Server code: writing a response directly

    1.A Using the PrintWriter from HttpServletResponse

    The PrintWriter from HttpServletResponse` permits writing data directly to the response that will be returned to the user. This bypasses any safety mechanisms built into any frameworks in use.

    Example:

    response.getWriter().write("<p>Hello, " + name + "!</p>");

    Mitigation

    Ban use of PrintWriter from HttpServletResponse. Alternatively, render JSP pages using request forwarding: request.getRequestDispatcher("/page.jsp").forward(...);

    Semgrep rule

    java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer

    1.B. Using the OutputStream from HttpServletResponse

    The OutputStream from HttpServletResponse permits writing data directly to the response that will be returned to the user. This bypasses any safety mechanisms built into any frameworks in use.

    Example:

    String template = "<p>Hello, " + name + "!</p>";
    response.getOutputStream().write(template.getBytes());

    References

    Mitigation

    Ban use of OutputStream from HttpServletResponse. Render JSP pages using request forwarding: request.getRequestDispatcher("/page.jsp").forward(...);.

    Semgrep rule

    java.lang.security.audit.xss.no-direct-response-writer.no-direct-response-writer

    2. JSP page: Variable is not explicitly escaped

    2.A. Any variable used without <c:out ...> tag

    The out tag from the JSTL taglib escapes the given value. Without this or another escaping method, data in the JSP will be unescaped. This could create XSS vulnerabilities.

    Example:

    <div>${userObj.name}</div>

    References

    Mitigation

    Require use of JSTL escapeXml function in every expression. Alternatively, require use of JSTL escapeXml function in every expression.

    Semgrep rule

    java.lang.security.audit.xss.jsp.use-escapexml.use-escapexml

    2.B.Any expression without escapeXml

    The escapeXml JSTL expression will escape XML characters. Any data rendered without this or another escaping method will be a potential site for XSS.

    Example:

    <div>${userObj.name}</div>

    References

    Mitigation

    Require use of JSTL escapeXml function in every expression. Alternatively, require use of JSTL escapeXml function in every expression.

    Semgrep rule

    java.lang.security.audit.xss.jsp.use-escapexml.use-escapexml

    3. JSP page: Variable in dangerous location

    3.A. Unquoted variable in HTML attribute

    Unquoted template variables rendered into HTML attributes is a potential XSS vector because an attacker could inject JavaScript handlers which do not require HTML characters. An example handler might look like: onmouseover=alert(1). HTML escaping will not mitigate this. The variable must be quoted to avoid this.

    Example:

    <div class=${classes}></div>

    References

    Mitigation

    Flag unquoted HTML attributes with Jinja expressions. Alternatively, always use quotes around HTML attributes.

    3.B. Variable in href attribute

    Template variables in a href value could still accept the javascript: URI. This could be a XSS vulnerability. HTML escaping will not prevent this. Use url_for to generate links.

    Example:

    <a href="${link}"></a>

    References

    Mitigation

    Flag template variables in href attributes.

    3.C. Variable in <script> block

    Template variables placed directly into JavaScript or similar are now directly in a code execution context. Normal HTML escaping will not prevent the possibility of code injection because code can be written without HTML characters. This creates the potential for XSS vulnerabilities, or worse.

    References

    Example:

    <script>var name = ${name};</script>

    Mitigation

    Ban template variables in <script> blocks.


    Not finding what you need in this doc? Ask questions in our Community Slack group, or see Support for other ways to get help.