XSS mitigation in ColdFusion, Part 1: Understanding HTML Contexts - Security Series #8.5.1

A long, long time has passed since my first post on Cross-Site Scripting. Looking back on it now, I realize that I have learned a lot since then. I do not think that post cuts the mustard anymore and I will need to do some writing to make up for that.

In the meantime, the topic of XSS came up on a discussion board a few weeks before I started writing this, and again on Ray's blog today, and I wanted to take some time to explore it in more depth. One common misconception about XSS mitigation in ColdFusion is that the best way to handle it is to use HTMLEditFormat() to output any user generated data. I had this same misconception for a long time and have helped to spread it.

While it is true that HTMLEditFormat() can stop many attacks in many locations in your applications, it is not a catch all for XSS. HTMLEditFormat() only works in the HTML block content context of your applications. Your applications have several other contexts where, if you use dynamic code, you can open up XSS vulnerabilities that HTMLEditFormat() cannot stop.

In this post, we will discuss these contexts, what the are, and why they need to be treated differently.

Vulnerable Contexts

Anytime that you use dynamic, user-provided content in your HTML pages you potentially create an XSS vulnerability; but you can implement the proper countermeasures to mitigate the risk.

That said, different contexts within the displayed pages need to be handled differently. Like I said, HTMLEditFormat() will not work everywhere.

The different contexts within HTML pages are:

  • HTML Contents
  • HTML Attributes
  • JavaScript
  • Style (CSS)
  • URL

Each of these context needs to be protected in a different way to defend against XSS attacks and, unfortunately, ColdFusion does not have the tools built-in to protect them all (If you're a ColdFusion hater, don't go getting all high-and-mighty. No language that I am aware of has everything you need built-in, hence the need for projects like ESAPI).

To mitigate the threat of XSS attacks, we must escape (or encode) untrusted data before it is displayed on-screen for the end user. ColdFusion has several built-in encoding functions, but they were not designed for XSS mitigation, they were designed to help display content that needs to be encoded on screen. The built-in ColdFusion functions for encoding are:

  • HTMLEditFormat()
  • JSStringFormat()
  • XMLFormat()
  • URLEncodedFormat()
  • HTMLCodeFormat()

We will talk more about these functions and why they do not work for securing our sites from XSS attacks in the next post. For now, I want to explain the "contexts" that I keep going on about.

Contexts

In this sense, we are using the word context as described in definition #2 at Dictionary.com.

2. the set of circumstances or facts that surround a particular event, situation, etc.

In HTML, we have situations in our code where certain things happen. For example, in the HTML Element Content context (for example, the space between two div tags), is where we place content that we want to rendered to the screen. Some of that content is surrounded by markup (<strong>, <em>, etc) which changes the way that the content is displayed. But there is no way that, in the HTML Element Content context that we can change the way that the content behaves. For that, we need to move into another context, an executable one.

Let's look at a small block of code.

HTML Contents Context


<div id="headline1">ColdFusion <em>is</em> awesome</div>

In this block, I am displaying text and changing the way it looks. But there is nothing I can do within this context to alter the text's behavior. For example, if I want to change the color of the text when I mouse over it, or if I want something to happen when I click on it, the HTML Content Context does not support that. I would need to move into a JavaScript or CSS context, which you will see shortly.

HTML Attribute Context

In the previous example, we also have another context, the HTML Attribute context (id="headline1"). The HTML attribute context is the context within the value of an HTML attribute , some of the time. I say "some of the time" because it is not always the case. There are some situations where the context inside of the quotes is not in the HTML Attribute context, but we'll get into that a bit later. For now just understand that for simple text attributes (id, class, name, value, size, etc) that the context is the HTML Attribute context.

Some quick examples.


<div id="headline1">ColdFusion <em>is</em> awesome</div>

<form action="process.cfm" method="post">
...
</form>

In the above examples, the values of the id, action, and method attributes are in the HTML Attribute context.

When is the HTML Attribute context NOT the HTML Attribute Context?

Answer, when it is in another context. Let's look at some examples.


<div id="headline1" onclick="alert('You clicked on the headeline ' + this.id);">ColdFusion <em>is</em> awesome</div>

The context switch is a subtle. You might be wondering, which context the value of the onclick attribute is in. Is it in the HTML attribute context or the JavaScript context?

The answer is that it is in the JavaScript context. The browser will parse and execute everything between the double quotes just as if it were inside of a <script> block.

Similar thing here:


<div id="headline1" style="color: red">ColdFusion <em>is</em> awesome</div>

In the above example I am using the style attribute of the <div> tag to alter the appearance of the text. What context is the value of the style attribute in? If you've been paying attention, you probably guessed that it is in the CSS context.

JavaScript Context


<script>
    document.getElementById("headline1").addEventListener("click", function(e) {
        alert('You clicked on the headeline ' + e.target.id);
    }
</script>

<div id="headline1">ColdFusion <em>is</em> awesome</div>

In this example, I have used the JavaScript context (between the script tags) to alter the behavior of the div tag in the HTML context. The javaScript context exists in between <script> tags or within a JavaScript event handlers' attribute's value in HTML elements. Event handlers like onclick, onblur, ommouseover, etc.


<div onclick="alert(123)"></div>
<div onblur="alert(123)"></div>
<div onmouseover="alert(123)"></div>

The text "alert(123)" in the above code are all within the JavaScript context of the HTML page, which means that the code will be parse and executed as JavaScript.

Another way to switch into the JavaScript Context is with the javascript URL format. Here is an example:


<a href="javascript: alert(123);return false;">My Link</a>

In this example, everything after the colon (:) is treated as JavaScript until the end quote leaves that context. Personally, I never use this means of switching into JS.

CSS Context

The CSS context of an HTML page occurs in between <style> blocks and in the style attribute of an html element (as we saw above).


<style>
body {
background-color: white;
{
</style>

In the above example, everything between the beginning and end style tags are in the CSS context.

Everything within the quoted values of the style attribute below is also in the CSS Context:


<div id="headline1" style="color: red">ColdFusion <em>is</em> awesome</div>

URL Context

FInally, we'll discuss the URL context. The URL context is one of the most confusing and is another situation where content with an HTML Attribute could be in a different context.

The URL Context is in the value of each parameter value of a GET HTTP request. THis can be confusing, because some think it is the whole URL or the whole query string. It is not. It is in each value.

For example, in the following URL the values in the URL context are "Test1" and "test2" (minus the quotes). This is important to remember, because when we work with user-provided data in this context we need to work with the correct pieces of data.


http://www.12robots.com/index.cfm?param1=Test1¶m2=test2

Here is an example where we have user-defined values in multiple contexts:


<a href="http://www.12robots.com/#url.pagename#.cfm?name=#url.name#&id=#url.id#">Edit</a>

In this example, the URL.pagename value is in the HTMLAttribute and url.name and URL.id are in the URL parameter context, and they each need to be treated differently.

Conclusion

I know that I have not given you many "answers" here, but this knowledge is important to understanding how we need to mitigate XSS risk. In my next post, I will discuss where the built-in ColdFusion functions fail to provide the protection that we need.

Reference: OWASP XSS Prevention Cheat Sheet

Comments
Damon's Gravatar Jason,

You mention ESAPI in your article. I have been working on porting the ESAPI for JavaEE to ColdFusion.

It can be found here: https://github.com/damonmiller/cfesapi/

In reference to your article, the DefaultEncoder would address most if not all of the items you mention: https://github.com/damonmiller/cfesapi/blob/master/org/owasp/esapi/reference/DefaultEncoder.cfc
# Posted By Damon | 3/10/11 9:41 AM
Jason Dean's Gravatar Damon,

That is awesome. You've gotten much further than I have. I started a CFESAPI project sometime back have worked on it on an off. I'm glad someone is making better progress than I did.

I will definitely be taking a look in the near future.

One thing I will point out to you, in case you didn't notice, but with the recent security hotfixes ESAPI 2.x is now being added to ColdFusion's /lib dir. So if someone is current on their CF8 or CF9 hotfixes they should already have the Java ESAPI loaded.

If it were my project, I would remove the internal calls to JavaLoader and require that ESAPI be in the CF lib dir. It's just easier that way.
# Posted By Jason Dean | 3/11/11 4:49 PM
Damon's Gravatar Thanks Jason. No I wasn't aware of the inclusion of ESAPI in the latest CF hotfixes. I'll look into that more.
# Posted By Damon | 3/23/11 3:29 PM
Ray V's Gravatar Hi Jason,

Thanks for the information. Great post!

Pete Freitag has a recent item regarding the ESAPI. http://www.petefreitag.com/item/788.cfm
# Posted By Ray V | 3/31/11 9:54 AM
Brian's Gravatar Was there a next post in this series?
# Posted By Brian | 1/24/12 11:17 AM
Jason Dean's Gravatar @brian, there is, but I have not finished it, so it is unpublished. I should finish it.
# Posted By Jason Dean | 1/24/12 11:32 AM
Mike Henke's Gravatar Second Brian's request. This first post was very good. Looking forward to a followup.
# Posted By Mike Henke | 5/22/12 2:28 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner