Struts 2 encode input parameters to avoid XSS - java

I have an application built with Struts 2. It has some issues with Cross-site scripting (XSS) attacks. I want to encode some of the actions input parameters in a similar fashion to JSP <c:out value="${somevalue}"/> Is there any easy approach to do this in Struts 2? Java API method would do fine.
EDIT I found this one - http://www.owasp.org/index.php/Talk:How_to_perform_HTML_entity_encoding_in_Java
Any experience with it?

You can use
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
${fn:escapeXml(someValue)}
There is also a Good API JSoup
Sanitize untrusted HTML
Problem
You want to allow untrusted users to supply HTML for output on your website (e.g. as comment submission). You need to clean this HTML to avoid cross-site scripting (XSS) attacks.
Solution
Use the jsoup HTML Cleaner with a configuration specified by a Whitelist.
String unsafe =
"<p><a href='http://example.com/' onclick='stealCookies()'>Link</a></p>";
String safe = Jsoup.clean(unsafe, Whitelist.basic());
// now: <p>Link</p>
So, all you basically need to do is the the following during processing the submitted text:
String text = request.getParameter("text");
String safe = Jsoup.clean(text, Whitelist.basic());
// Persist 'safe' in DB instead.
There is struts2securityaddons
This project contains additional configuration, interceptors, and other code used to improve the security of struts 2 applications.
See also
XSS Prevention oin Java
Prevent jsp from XSS
struts2securityaddons

Escaping input parameters as an XSS prevention mean has several disadvanteges, especially:
You can't be certain about destination of the particular input data, therefore you can't choose proper escaping scheme.
Escaping input data masks lack of output escaping. Without consistent output escaping, you can still pass unescaped data to the unescaped output accidentially.
Presence of escaping complicates data processing.
Therefor it would be better to apply consistent output escaping instead.
See also:
OWASP XSS Prevention Cheat Sheet

There is no easy, out of the box solution against XSS with struts 2 tags. 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.
Modify s:property tag so it can take extra attributes stating what sort of escaping is required (escapeHtmlAttribute="true" etc.). This involves creating a new Property and PropertyTag classes. The Property class uses OWASP ESAPI api for the escaping.
Change freemarker templates to use the new version of s:property and set the escaping.
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.

Related

Preventing xss attack in java web app while saving actual values in database

In a Recent scan of our java based web application through AppScan it was found that the application was prone to XSS attacks.
I did my research and found that a ServletFilter was probably the easiest way to protect the application.
I introduced the filter where I extended HttpServletRequestWrapper (because java does not allow request param to be changed, there is no request.setParam method). I introduced a sanitize method there and here is what it does
result = ESAPI.encoder().canonicalize( input);
// Avoid null characters
result = result.replaceAll("\0", "");
// Clean out HTML
result = Jsoup.clean( result, Whitelist.none() );
Post this change, it was good, I tested for XSS vulnerabilites myself and most of them were fixed. But this posed another problem. Suppose I have a form to create a product, and in product name a user enters something like
<script>alert('somethingStupid')</script>
Now Ideally I should be able to save this to database, but still be protected from XSS attack. Not sure what to do in my filter or anywhere else to achieve this.
HTML-injection is an output-stage issue, caused by forgetting to encode text when injecting it into a context where characters are special. ESAPI offers encoders for various contexts, as discussed by #Zakaria. If you use these consistently, each in the correct context, you have fixed injection-related XSS issues.
If you are using purely JSTL tags like <c:out> for your templating, these will also HTML-escape by default. In general, it is best to generate HTML using a templating system that works HTML-escaping out for you automatically, because otherwise you are likely to forget to manually encodeForHTML occasionally.
(Aside: on project where I am compelled to use the mostly-terrible owasp-esapi-java library, my preference is for encodeForXML over the HTML encoders, as it produces output that is safe for HTML content and quoted attribute values whilst not needlessly attempting to produce entity references for non-ASCII characters. I would typically try to avoid injecting into JavaScript string literals; it is typically easier and more maintainable to inject run-time content into HTML data- attributes and read them from separate JavaScript DOM code.)
Trying to filter out HTML at the input stage is a lamentably still-popular but completely misguided approach. It prevents you from entering HTML-like input when you need to—as you have found out, with the <script> example. Indeed, if StackOverflow used such an input filter we would not be able to have this conversation.
What's more, it's not resilient: there are many ways to smuggle potential injections past input filters. To make a filter effective you'd have to consider blocking pretty much all punctuation, which is generally not considered acceptable. Plus, any data that gets into your application by means other than request parameters won't be vetted.
Input validation is great for enforcing business rules on the formats of particular input fields, and can be used to filter out input that you never want, like control characters. But it's the wrong place to be worrying about escaping or removing HTML. The time to do that is when you're creating HTML.
Cross Site Scripting (XSS) is a security issue which occurs when there is no mechanism of validating user input so the result will be an exploitable javascript code generally.
3 types of XSS are known : Reflexive XSS, DOM-based XSS and Persistant XSS.
In your case and since you're using OWASP ESAPI, canonicalizing inputs is not enough, sure it's a good way to defense against Untrusted URL in a SRC or HREF attribute but it's not enough.
You should Follow thess Rules : Source ( XSS (Cross Site Scripting) Prevention Cheat Sheet of OWASP ) (here are some rules for further reading follow the link) :
1- HTML Escape Before Inserting Untrusted Data into HTML Element Content: see the example :
String safe = ESAPI.encoder().encodeForHTML( request.getParameter( "input" ) );
2- Attribute Escape Before Inserting Untrusted Data into HTML Common Attributes :
String safe = ESAPI.encoder().encodeForHTMLAttribute( request.getParameter( "input" ) );
3- JavaScript Escape Before Inserting Untrusted Data into JavaScript Data Values:
String safe = ESAPI.encoder().encodeForJavaScript( request.getParameter( "input" ) );

Escape HTML in JSON with PlayFramework2

I am using PlayFramework2 and I can't find a way to properly handle HTML escaping.
In the template system, HTML entities are filtered by default.
But when I use REST requests with Backbone.js, my JSON objects are not filtered.
I use play.libs.Json.toJson(myModel) to transform an Object into a String.
So, in my controller, I use return ok(Json.toJson(myModel)); to send the response ... but here, the attributes of my model are not secured.
I can't find a way to handle it ...
Second question :
The template engine filters HTML entities by default, this means that we have to store into our database the raw user inputs.
Is it a save behaviour ?
Third questdion :
Is there in the PlayFramework a function to manualy escape strings ? All those I can find require to add new dependencies.
Thanks !
Edit : I found a way at the Backbone.js templating level :
- Use myBackboneModel.escape('attr'); instead of myBackboneModel.get('attr');
Underscore.js templating system also includes that options : <%= attr %> renders without escaping but <%- attr %> renders with escaping !
Just be careful to the efficiency, strings are re-escaped at each rendering. That's why the Backbone .create() should be prefered.
The best practices on XSS-attacks prevention usually recommend you to reason about your output rather than your input. There's a number of reasons behind that. In my opinion the most important are:
It doesn't make any sense to reason about escaping something unless you exactly know how you are going to output/render your data. Because different ways of rendering will require different escaping strategies, e.g. properly escaped HTML string is not good enough to use it in Javascript block. Requirements and technologies change constantly, today you render your data one way - tomorrow you might be using another (let's say you will be working on a mobile client which doesn't require HTML-escaping, because it doesn't use HTML at all to render data) You can only be sure about proper escaping strategy while rendering your data. This is why modern frameworks delegate escaping to templating engines. I'd recommend reviewing the following article: XSS (Cross Site Scripting) Prevention Cheat Sheet
Escaping user's input is actually a destructive/lossy operation – if you escape user's input before persisting it to a storage you will never find out what was his original input. There's no deterministic way to 'unescape' HTML-escaped string, consider my mobile client example above.
That is why I believe that the right way to go would be to delegate escaping to your templating engines (i.e. Play and JS-templating engine you're using for Backbone). There's no need to HTML-escape string you serialize to JSON. Notice that behind the scenes JSON-serializer will JSON-escape your strings, e.g. if you have a quote in your string it will be properly escaped to ensure resulting JSON is correct, because it's a JSON serializer after all that's why it only cares about proper JSON rendering, it knows nothing about HTML (and it shouldn't). However when you rendering your JSON data in the client side you should properly HTML-escape it using the functionality provided by the JS-templating engine you're using for Backbone.
Answering another question: you can use play.api.templates.HtmlFormat to escape raw HTML-string manually:
import play.api.templates.HtmlFormat
...
HtmlFormat.escape("<b>hello</b>").toString()
// -> <b>hello</b>
If you really need to make JSON-encoder escape certain HTML strings, a good idea might be to create a wrapper for them, let's say RawString and provide custom Format[RawString] which will also HTML-escape a string in its writes method. For details see: play.api.libs.json API documentation

Is URLEncoder.encode(string, "UTF-8") a poor validation?

In a portion of my J2EE/java code, I do a URLEncoding on the output of getRequestURI() to sanitize it to prevent XSS attacks, but Fortify SCA considers that poor validation.
Why?
The key point is that you need to convert HTML special characters to HTML entities. This is also called "HTML escaping" or "XML escaping". Basically, the characters <, >, ", & and ' needs to be replaced by <, >, ", & and '.
URL encoding does not do that. URL encoding converts URL special characters to percent-encoded values. This is not HTML escaping.
In case of web applications, HTML escaping is normally to be done in the view side, exactly there where you're redisplaying user-controlled input. In case of a Java EE web applications, that depends on the view technology you're using.
If the webapp is using modern Facelets view technology, then you don't need to escape it yourself. Facelets will already implicitly do that.
If the webapp is using legacy JSP view technology, then you need to ensure that you're using JSTL <c:out> tag or fn:escapeXml() function to redisplay user-controlled input.
<c:out value="${bean.foo}" />
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
If the webapp is very legacy or bad designed and using servlets or scriptlets to print HTML, then you've a bigger problem. There are no builtin tags or functions, let alone Java methods which can escape HTML entities. You should either write some escape() method yourself or use the Apache Commons Lang StringEscapeUtils#escapeHtml() for this. Then you need to ensure that you're using it everywhere you're printing user-controlled input.
out.print("<p>" + StringEscapeUtils.escapeHtml(request.getParameter("foo")) + "</p>");
Much better would be to redesign that legacy webapp to use JSP with JSTL.
URL encoding does not affect certain significant characters including single quote (') and parentheses, so URL encoding will pass through unchanged certain payloads.
For example,
onload'alert(String.fromCharCode(120))'
will be treated by some browsers as a valid attribute that can result in code execution when injected inside a tag.
The best way to avoid XSS is to treat all untrusted inputs as plain text, and then when composing your output, properly encode all plain text to the appropriate type on output.
If you want to filter inputs as an additional layer of security, make sure your filter treats all quotes (including back-tick) and parentheses as possible code, and disallow them unless the make sense for that input.

How to escape JavaScript in an HTML String while keeping the HTML unescaped?

We have a webapplication. At some points there is a JavaScript based WSIWYG / RichText Editor. It filters some JavaScript but uses HTML text to format it's content.
Unfortunately it does not filter all JavaScript. I was able to proof a XSS attack with an event handler. I think the JavaScript client side filtering of JavaScript is not safe at all, because at client side it can be manipulated.
So I would like to filter or escape JavaScript at the server side. I had a short look at ESAPI for Java. But we have a requirement, I don't know if it is special or a problem:
The HTML elements the editor uses should not be filtered or escaped, only JavaScript. The HTML should be ordinary rendered in the browser.
Is there a safe way, to escapce or filter JavaScript while keeping the HTML like it is?
Does ESAPI or any other API help me doing this?
How do I do it.
Thanks in advance.
It is difficult to state what escaping schemes have to be used to escape JavaScript without knowing whether the application is vulnerable to DOM-based XSS attacks or the run-of-the-mill (reflected and persistent) XSS attacks.
ESAPI for Java will help in both cases though. In the case of DOM-based XSS attacks, you would need to encode the unsafe data multiple times (and using different encoding schemes if necessary) to ensure that each parser in the parsing chain will not be subject to XSS attacks. In the case of reflected or persistent XSS attacks, you'll usually need to apply the escaping only once, in the appropriate context.
It should be kept in mind that, allowing raw HTML on its own is also unsafe, resulting in XSS. You might want to take a look at a different approach to sanitizing inputs; using AntiSamy for filtering HTML might be warranted in this case.
You need to parse the HTML and reject any tags and attributes that aren't in a strict whitelist of safe tags/attributes.
The whitelist would not include tags like <script>, <style>, or <link>, and it wouldn't include attributes like onclick, onload, or style.
You should also make sure that href and src attributes use the http or https protocols (or a relative path), and not javascript:.

How to implement a possibility for user to post some html-formatted data in a safe way?

I have a textarea and I want to support some simplest formatting for posted data (at least, whitespaces and line breaks).
How can I achieve this? If I will not escape the response and keep some html tags then it'll be a great security hole. But I don't see any other solution which will allow text formatting in browser.
So, I probably should filter user's input. But how can I do this? Are there any ready to use solutions? I'm using JSF so are there any smart component which filters everything except html tags?
Use a HTML parser which supports HTML filtering against a whitelist like Jsoup. Here's an extract of relevance from its site.
Sanitize untrusted HTML
Problem
You want to allow untrusted users to supply HTML for output on your website (e.g. as comment submission). You need to clean this HTML to avoid cross-site scripting (XSS) attacks.
Solution
Use the jsoup HTML Cleaner with a configuration specified by a Whitelist.
String unsafe =
"<p><a href='http://example.com/' onclick='stealCookies()'>Link</a></p>";
String safe = Jsoup.clean(unsafe, Whitelist.basic());
// now: <p>Link</p>
And then to display it with whitespace preserved, apply CSS white-space: pre-wrap; on the HTML element where you're displaying it.
No all-in-one JSF component comes to mind.
Is there some reason why you need to accept HTML instead of some other markup language, such as markdown (which is what StackOverflow uses)?
http://daringfireball.net/projects/markdown/
Not sure what kind of tags you'd want to accept that wouldn't be covered by md or a similar formatting language...

Categories

Resources