My personal opinion is that you should avoid using JSP/ASP/PHP/etc pages. Instead output to an API similar to SAX (only designed for calling rather than handling). That way there is a single layer that has to create well formed output.
The how-to-prevent-xss has been asked several times. You will find a lot of information in StackOverflow. Also, OWASP website has an XSS prevention cheat sheet that you should go through.
On the libraries to use, OWASP's ESAPI library has a java flavour. You should try that out. Besides that, every framework that you use has some protection against XSS. Again, OWASP website has information on most popular frameworks, so I would recommend going through their site.
If you want to automatically escape all JSP variables without having to explicitly wrap each variable, you can use an EL resolver as detailed here with full source and an example (JSP 2.0 or newer), and discussed in more detail here:
For example, by using the above mentioned EL resolver, your JSP code will remain like so, but each variable will be automatically escaped by the resolver
...
<c:forEach items="${orders}" var="item">
<p>${item.name}</p>
<p>${item.price}</p>
<p>${item.description}</p>
</c:forEach>
...
If you want to force escaping by default in Spring, you could consider this as well, but it doesn't escape EL expressions, just tag output, I think:
http://forum.springsource.org/showthread.php?61418-Spring-cross-site-scripting&p=205646#post205646
Note: Another approach to EL escaping that uses XSL transformations to preprocess JSP files can be found here:
http://therning.org/niklas/2007/09/preprocessing-jsp-files-to-automatically-escape-el-expressions/
I would suggest regularly testing for vulnerabilities using an automated tool, and fixing whatever it finds. It's a lot easier to suggest a library to help with a specific vulnerability then for all XSS attacks in general.
Skipfish is an open source tool from Google that I've been investigating: it finds quite a lot of stuff, and seems worth using.
There is no easy, out of the box solution against XSS. The OWASP ESAPI API has some support for the escaping that is very usefull, and they have tag libraries.
My approach was to basically to extend the stuts 2 tags in following ways.
If you didn't want to modify the classes in step 1, another approach would be to import the ESAPI tags into the freemarker templates and escape as needed. Then if you need to use a s:property tag in your JSP, wrap it with and ESAPI tag.
I have written a more detailed explanation here.
http://www.nutshellsoftware.org/software/securing-struts-2-using-esapi-part-1-securing-outputs/
I agree escaping inputs is not ideal.
Managing XSS requires multiple validations, data from the client side.
I had great luck with OWASP Anti-Samy and an AspectJ advisor on all my Spring Controllers that blocks XSS from getting in.
public class UserInputSanitizer {
private static Policy policy;
private static AntiSamy antiSamy;
private static AntiSamy getAntiSamy() throws PolicyException {
if (antiSamy == null) {
policy = getPolicy("evocatus-default");
antiSamy = new AntiSamy();
}
return antiSamy;
}
public static String sanitize(String input) {
CleanResults cr;
try {
cr = getAntiSamy().scan(input, policy);
} catch (Exception e) {
throw new RuntimeException(e);
}
return cr.getCleanHTML();
}
private static Policy getPolicy(String name) throws PolicyException {
Policy policy =
Policy.getInstance(Policy.class.getResourceAsStream("/META-INF/antisamy/" + name + ".xml"));
return policy;
}
}
You can get the AspectJ advisor from the this stackoverflow post
I think this is a better approach then c:out particular if you do a lot of javascript.
If you want to make sure that your $
operator does not suffer from XSS hack you can implement ServletContextListener
and do some checks there.
The complete solution at: http://pukkaone.github.io/2011/01/03/jsp-cross-site-scripting-elresolver.html
@WebListener
public class EscapeXmlELResolverListener implements ServletContextListener {
private static final Logger LOG = LoggerFactory.getLogger(EscapeXmlELResolverListener.class);
@Override
public void contextInitialized(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener initialized ...");
JspFactory.getDefaultFactory()
.getJspApplicationContext(event.getServletContext())
.addELResolver(new EscapeXmlELResolver());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener destroyed");
}
/**
* {@link ELResolver} which escapes XML in String values.
*/
public class EscapeXmlELResolver extends ELResolver {
private ThreadLocal<Boolean> excludeMe = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
@Override
public Object getValue(ELContext context, Object base, Object property) {
try {
if (excludeMe.get()) {
return null;
}
// This resolver is in the original resolver chain. To prevent
// infinite recursion, set a flag to prevent this resolver from
// invoking the original resolver chain again when its turn in the
// chain comes around.
excludeMe.set(Boolean.TRUE);
Object value = context.getELResolver().getValue(
context, base, property);
if (value instanceof String) {
value = StringEscapeUtils.escapeHtml4((String) value);
}
return value;
} finally {
excludeMe.remove();
}
}
@Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return null;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base){
return null;
}
@Override
public Class<?> getType(ELContext context, Object base, Object property) {
return null;
}
@Override
public boolean isReadOnly(ELContext context, Object base, Object property) {
return true;
}
@Override
public void setValue(ELContext context, Object base, Object property, Object value){
throw new UnsupportedOperationException();
}
}
}
Again: This only guards the $
. Please also see other answers.
Source: Stackoverflow.com