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-writer1.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-writer2. 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-escapexml2.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-escapexml3. 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
- Template engines: Why default encoders are not enough
- Safely including data for JavaScript in a Django template
json_script
documentation
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.