How do I prevent people from doing XSS in Spring MVC?
Solution 1
In Spring you can escape the html from JSP pages generated by <form>
tags. This closes off a lot avenues for XSS attacks, and can be done automatically in three ways:
For the entire application in the web.xml
file:
<context-param>
<param-name>defaultHtmlEscape</param-name>
<param-value>true</param-value>
</context-param>
For all forms on a given page in the file itself:
<spring:htmlEscape defaultHtmlEscape="true" />
For each form:
<form:input path="someFormField" htmlEscape="true" />
Solution 2
I use Hibernate Validator via @Valid
for all input objects (binding and @RequestBody
json, see https://dzone.com/articles/spring-31-valid-requestbody). So @org.hibernate.validator.constraints.SafeHtml
is a good solution for me.
Hibernate SafeHtmlValidator
depends on org.jsoup
, so it's needed to add one more project dependencies:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.1</version>
</dependency>
For bean User
with field
@NotEmpty
@SafeHtml
protected String name;
for update attempt with value <script>alert(123)</script>
in controller
@PutMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
public void update(@Valid @RequestBody User user, @PathVariable("id") int id)
or
@PostMapping
public void createOrUpdate(@Valid User user) {
is thrown BindException
for binding and MethodArgumentNotValidException
for @RequestBody
with default message:
name may have unsafe html content
Validator works as well for binding, as before persisting. Apps could be tested at http://topjava.herokuapp.com/
UPDATE: see also comment from @GuyT
CVE-2019-10219 and status of @SafeHtml
We have been made aware of a CVE-2019-10219 related to the @SafeHtml constraint and it was fixed in both 6.0.18.Final and 6.1.0.Final....
However, we came to the conclusion that the @SafeHtml constraint was fragile, highly security-sensitive and depending on an external library that wasn’t designed for this purpose. Having it included in core Hibernate Validator was not a very good idea. That’s why we deprecated it and marked it for removal.There is no magic plan here so our users will have to maintain this constraint themselves
Resume for myself: it is safe and could be used, until solution better be found.
UPDATE: due to remove @SafeHtml/SafeHtmlValidator
from hibernate.validator
use own NoHtmlValidator
, see https://stackoverflow.com/a/68888601/548473
Solution 3
Try XSSFilter.
Solution 4
When you are trying to prevent XSS, it's important to think of the context. As an example how and what to escape is very different if you are ouputting data inside a variable in a javascript snippet as opposed to outputting data in an HTML tag or an HTML attribute.
I have an example of this here: http://erlend.oftedal.no/blog/?blogid=91
Also checkout the OWASP XSS Prevention Cheat Sheet: http://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
So the short answer is, make sure you escape output like suggested by Tendayi Mawushe, but take special care when you are outputting data in HTML attributes or javascript.
Doug
Updated on July 08, 2022Comments
-
Doug almost 2 years
What should I do to prevent XSS in Spring MVC? Right now I am just putting all places where I output user text into JSTL
<c:out>
tags orfn:escapeXml()
functions, but this seems error prone as I might miss a place.Is there an easy systematic way to prevent this? Maybe like a filter or something? I'm collecting input by specifying
@RequestParam
parameters on my controller methods. -
Doug about 14 yearsI put <spring:htmlEscape defaultHtmlEscape="true" /> in an include file that I include in all my pages, but it doesn't seem to make a difference. Will that tag cause ${param.q} to be escaped?
-
Andreas almost 14 yearsIf you use the resulting strings inside a HTML attribute or a Javascript,
defaultHTMLEscape
is not enough, then use the<c:out />
-tag. It seems like defaultHtmlEscape does not escape all html-characters. It escapes e.g. '<' '>' or '&' but double quotation marks"
were not escaped for me. This can lead to problems if the resulting string is used e.g. in a html-attribute or a javascript. (See also answer by Erlend) -
Andreas almost 14 years"take special care" = use the
<c:out />
-tag when you output data in HTML attributes or javascript. (see my comment at Tendayi Mawushe's answer) -
Erlend almost 14 yearsWell, it's more than just using <c:out />. Javascript has other control characters than HTML, and can be attacked in different ways, and so needs to be handled using other types of escaping. A simple example:var a = '<c:out ... />'; var b = '<c:out ... />'; If the input in a is a single backslash, script in b will run. Escaping depends on context.
-
Manish Mahajan about 10 yearsMy application stopped working after configuring for xssflt.jar. As soon as i removed filter and filter mapping from web xml it started working.
-
Jack over 8 yearsI add the context-param to my web.xml but it does not work.
-
Jack over 8 yearsHow can I use this in a Maven based project?
-
pinkpanther almost 8 yearsIs it for input encoding or output escaping?
-
Dhanu K almost 6 yearsit’s not working for form type multipart that means when we sending files with form this filtering is not working, is my query correct? If yes, is there any solution? Or what’s wrong with me
-
SPoint over 5 yearsyour code is a bad pattern to avoid XSS. You don't need to do à Blacklist with replace approach. You need to encode output to really fight XSS !
-
GabiM about 5 yearsBlacklisting your input like presented in this answer, as @SPoint also said, is a bad approach. You need a two pronged solution: 1 escape out put and 2 whitelist input. Whitelisting restricts what the user is allowed to submit as opposed to blacklisting where you allow anything and hope to clean the input yourself
-
GuyT about 4 yearsPlease note this is deprecated now due to security issues stackoverflow.com/questions/58913428/…