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.