I have to say I rather disagree with the accepted answer of apparently escaping on output to prevent XSS.
I believe the better approach is to sanitize on input which can easily be achieved with an aspect so that you don't have to put it all over the place. Sanitizing is different than escaping.
You can't just blindly escape:
- You may want users to enter a subset of HTML (aka links and bold tags).
- Escaping does not prevent XSS
I recommend using OWASP Antisammy library with an Aspect or @futtta's recommendation of the filter.
Below is an aspect I wrote to sanitize user input using Spring MVC annotations (since we use that for all of our input).
@SuppressWarnings("unused")
@Aspect
public class UserInputSanitizerAdivsor {
@Around("execution(@RequestMapping * * (..))")
public Object check(final ProceedingJoinPoint jp) throws Throwable {
Object[] args = jp.getArgs();
if (args != null) {
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if (o != null && o instanceof String) {
String s = (String) o;
args[i] = UserInputSanitizer.sanitize(s);
}
}
}
return jp.proceed(args);
}
}
You will still have to escape on output for non rich-text fields but you will never (and I believe should never) have malicious data in your database.
If you don't want to sanitize on certain inputs you can always make annotation that will make the aspect not sanitize.
The other reason you don't want malicious data in your database is if you provide any sort REST API to the Internet. You may do the right thing on output but your mashup partners may not.
Sanitizing input or blocking input is ok (I mean most people have file upload limit right?). Most of the fields in a web application don't need script tags to be entered and more importantly most of your users probably do not need or want to enter script tags (obvious exception is stack overflow answers).