AppSec Blog

How to Prevent XSS Without Changing Code

To address security defects developers typically resort to fixing design flaws and security bugs directly in their code. Finding and fixing security defects can be a slow, painstaking, and expensive process. While development teams work to incorporate security into their development processes, issues like Cross-Site Scripting (XSS) continue to plague many commonly used applications.

In this post we'll discuss two HTTP header related protections that can be used to mitigate the risk of XSS without having to make large code changes.

HttpOnly
One of the most common XSS attacks is the theft of cookies (especially session ids). The HttpOnly flag was created to mitigate this threat by ensuring that Cookie values cannot be accessed by client side scripts like JavaScript. This is accomplished by simply appending "; HttpOnly" to a cookie value. All modern browsers support this flag and will enforce that the cookie cannot be accessed by JavaScript, thereby preventing session hijacking attacks.

Older versions of the Java Servlet specification did not provide a standard way to define the JSESSIONID as "HttpOnly". As of Servlet 3.0, the HttpOnly flag can be enabled in web.xml as follows:

<session-config>
  <cookie-config>
    <http-only>true</http-only>
  </cookie-config>
</session-config>

Aside from this approach in Servlet 3.0, older versions of Tomcat allowed the HttpOnly flag to be set with the vendor-specific "useHttpOnly" attribute in server.xml. This attribute was disabled by default in Tomcat 5.5 and 6. But, starting with Tomcat 7, the "useHttpOnly" attribute is enabled by default. So, even if you configure web.xml to be "false" in Tomcat 7, your JSESSIONID will still be HttpOnly unless you change the default behavior in server.xml as well.

Alternatively, you can programmatically add an HttpOnly cookie directly to the request using the following code:
String cookie = "mycookie=test; Secure; HttpOnly";
response.addHeader("Set-Cookie", cookie);

Fortunately, the Servlet 3.0 API was also updated to with a convenience method called setHttpOnly for adding the HttpOnly flag:
String cookie = "mycookie=test; Secure; HttpOnly";
response.addHeader("Set-Cookie", cookie);

Content Security Policy
Content Security Policy (CSP) is a mechanism to help mitigate injection vulnerabilities like XSS by defining a list of approved sources of content. For example, approved sources of JavaScript can be defined to be from certain origins and any other JavaScript would not be allowed to execute. The official HTTP header used to define CSP policies is Content-Security-Policy and can be used like this:

Content-Security-Policy:
default-src 'none';
script-src https://*.sanscdn.org
           https://ssl.google-analytics.com;
style-src 'self'
img-src https://*.sanscdn.org
font-src https://*.sanscdn.org

In this example you can see that CSP can be used to define a whitelist of allowable content sources using default-src 'none' and the following directives:
- script-src - scripts can only be loaded from a specfic content delivery network (CDN) or from Google Analytics
- style-src - Styles can only be loaded from the current origin
- img-src and font-src - images and fonts can only be loaded from the CDN

By using the Content-Security-Policy header with directives like this you can easily harden your application against XSS. It sounds easy enough but there are some important limitations. CSP requires that there are no inline scripts or styles in your application. This means that all JavaScript in your application has to be externalized into .js files. Basically, you can't have inline <script> tags or call any functions which allow JavaScript execution from strings (e.g. eval, setTimeout, setInterval). This can be a problem for legacy applications that need to be refactored.

As a result, the CSP specification also provides a Content-Security-Policy-Report-Only header that does not block any scripts in your application from running but simply sends JSON formatted reports so that you can be alerted when something might have broken as a result of CSP. By enabling this header, you can test and update your app slowly over time while gaining visibility into areas that need to be refactored.

If you'd like to learn more about protecting your Java and web-based applications sign up for DEV541: Secure Coding in Java being held in Reston, VA starting March 9.

3 Comments

Posted January 30, 2015 at 6:54 PM | Permalink | Reply

Phil

Good additional security controls to minimize the risk exposure. Quick question regarding CSP and its limitation. Assuming you externalize all your Javascript source, does CSP prevent XSS when you Javascript source is accepting an input from querystring parameter that can be tampered with?
For example, I've tested few web applications (poorly designed IMO) and saw a common trend where the script accept an input (string) from a querystring parameter and make use of that string as part of execution, typically an error message. Does that make sense?

Posted March 5, 2015 at 8:27 PM | Permalink | Reply

Eric Johnson

Phil, are you asking if the parameter is used to define the script src location via a request parameter? For example,

Posted February 20, 2015 at 9:22 PM | Permalink | Reply

Ryan Barnett

Another interesting XSS defense "without changing code" is to leverage a web application firewall (WAF) to dynamically inject defensive code into html response data. For example ''" the open source WAF ModSecurity can inject two different client-side programs to help deal with XSS in the browser:
1) DOMPurify ''" https://github.com/cure53/DOMPurify, and
2) MentalJS ''" https://github.com/hackvertor/MentalJS
There is an online demo showing this usage here:
http://www.modsecurity.org/demo-deny-noescape.html

Post a Comment






Captcha


* Indicates a required field.