ColdFusion Security Tips



Written for OWASP



Taco Fleur

ColdFusion security tips

taco.fleur@.au

(sponsor of this article)

Wednesday, 23 January 2008

About the author

Taco Fleur is a ColdFusion programmer with approx. 10 years of ColdFusion experience, and is a full supporter of the product. He is currently working for .au the Australian business directory/search engine.

Introduction

Over the years ColdFusion has sometimes received a bad name for its security, I truly believe this was due to ColdFusion being such an easy language to pick up and work with. This meant that web designers with no formal programming education could program applications easily and quickly, the downside of that was that some of these applications would be easy to break/hack due to the lack of security knowledge that would have come with a programming degree.

Following are some security tips which I hope will help novices to make ColdFusion applications more secure. And don’t forget, don’t stop with these security tips, they are not meant to be the ultimate protection for your site.

I’ve taken every care possible to be accurate and provide easy to follow examples, if you find any errors, spelling or grammar mistakes, it would be much appreciated if you could let me know on taco.fleur@.au

Please note: this document is currently a work in progress

Index

1. SQL Injection

2. Database Logins

3. Logging

4. XSS (Cross Site Scripting)

5. Cookie Hijacking

6. Proper Error Handling

7. Input Validation

8. Securing Protected Areas

9. Forms being submitted outside of your domain

10. Automated data mining

SQL Injection

What is SQL injection?

SQL Injection is the injection of a malicious SQL statement by a hacker. It transforms your normally safe SQL statement to one that could delete records, drop tables, and much more depending on the rights the user on the ODBC connection has.

Let’s go to a simple example;

SELECT myColumn

FROM myTable

WHERE myIdentity = #url.myIdentity#

The above query would get a record from your database based upon the value of url.myIdentity. You could trust the input to always be an integer like; 1,2,3,4,5… 101 etc. but what if someone modified the URL value (which is not hard to do) to 1; DELETE+FROM+myTable

Your previously safe SQL statement would then be injected with “DELETE FROM myTable” and turn into;

SELECT myColumn

FROM myTable

WHERE myIdentity = 1; DELETE FROM myTable

When the above SQL statement reaches your database it would first execute

SELECT myColumn

FROM myTable

WHERE myIdentity = 1

and then it would execute “DELETE FROM myTable” which would delete all records from you table.

This is just the tip of the iceberg!

Solution

You should never trust input from a user, and always validate it, we’ll talk more about that later. There are two solutions, and you should probably use both at the same time.

The first is to use

SELECT myColumn

FROM myTable

WHERE myIdentity =

The cfqueryparam tag would check if the value of #url.myIdentity# is actually an integer, as is expected, and if not, it will throw an error. This will prevent the SQL statement from ever reaching the database.

The second step is to convert numeric characters that occur at the beginning of a string to a number with the ColdFusion function val().

url.myIdentity = val( url.myIdentity );

Which would turn the URL value “1;DELETE+FROM+myTable” into “1”, thus removing the malicious code, and the query doesn’t throw an error.

You could and probably should use Regular Expression to sanitize the input, but I’m trying to keep this document simple.

Database Logins

It is highly recommended to always allow the minimum rights to a database login. After you have created your database you should create separate logins for several areas and functions. The type of access and functions depends on your database platform, but let’s take a look at the obvious ones.

If parts of your application only SELECTS records from the database, then the only access rights to the login should obviously be SELECT rights. That login should not have access to DELETE, DROP and any others that are not required.

Let’s take for example .au, the search functionality only requires the login to have access to SELECT, so we could have created a user called user_frontend and only assign rights to use SELECT to it. This would mean the login would never be able to execute any DROP, INSERT, GRANT or other statements.

To do this you can use your database admin interface, or you can use the ColdFusion administrator and go to Data Sources > Select Data Source > click Show Advanced Settings > and tick the appropriate SQL this login is allowed to execute.

Obviously you would need to modify the rights based on the access required, but always keep it to the bare minimum.

Logging

Logging is mostly overlooked as playing an important part in securing an application; in reality it plays a very important part in security. Without proper logging you might never get to know that someone is executing an automated password attack on your website, trying to find administrator areas, or other holes in your application.

To log 404 errors you should setup a custom error in your web server. This varies from web server to web server.

In IIS you can follow the following steps;

1. Navigate to the website in question under IIS

2. Right click the website and select “Properties”

3. Click the “Home directory” tab

4. Click on “Configuration”

5. Double click the ColdFusion file extension .cfm

6. Check the box “Verify that file exists”

7. Do this for all ColdFusion file extensions

8. Do the same under wildcard application maps

9. Click “OK” when done

10. Click the “Custom errors” tab

11. Scroll down to the 404 error and double click it

12. Change message type to URL

13. Enter /404.cfm

14. And click OK to get out of all the screens

Now we need to create a ColdFusion page that will log all 404 errors to a database and email them. You might think that emailing will fill up your email box, but realistically, your application should not have any 404 errors at all, and therefore you would only be notified about a 404 when someone is trying to do things they are not supposed to, or someone followed an outdated link, in which case you would want to make sure that link get updated.

The ColdFusion page would look something like the following;

404 Error on .au

Script name: #cgi.script_name#

Query: #cgi.query_String#

Referer: #cgi.http_referer#

Date Time: #lsDateFormat( now() )# #lsTimeFormat( now() )#

Remote Address: #cgi.remote_addr#

Reverse DNS: #request.rDNS#

INSERT INTO [error404] (

[url]

, [ipAddress]

, [reverseDNS]

, [userAgent]

, [cookie]

)

VALUES (

,

,

,

,

)

404 Error

Some text here explaining to the user that they followed an outdated link, and maybe some links to other actions they might want to perform

We always want to adhere to the Internet rules, and make sure the search engines find a 404 error when they request an outdated link, which is why we return a 404 error in the header with the tag.

Then we email the error to support @ your domain. I’d like to note that request.rDNS is not a native function of ColdFusion. Getting the reverse DNS gives you more information about the individual who requested the 404, I believe it’s an important piece of information to include, however it requires some custom written classes, which would be to detailed for this article. Please see for any resources on reverse DNS in ColdFusion.

And finally, we log the 404 error in the database. If you want to go further and gain more protection, you could log the requests in the application scope and start checking whether more than 60 x 404 requests have been made in a time period of one minute, as that would mean 1 request per each second, and you can be assured that would be an automated attack. Based on this information you could prevent further access to the site.

XSS (Cross Site Scripting)

Cookie Hijacking

I have to say that the jury is still out on the following functionality I came up with. I am pretty sure it protects or at least makes a malicious users’ life more miserable. But I can’t say for sure whether it is fool proof, I’ve been told and I know that an IP can be spoofed, but I do believe that no data can be received back by the user making the request with a hijacked cookie.

If you have any other information or thoughts about this solution, please do let me know on taco.fleur@.au

In your application file you would set a cookie, you would put this in the onSessionStart or alternatively you would it in the application.cfm and first check if it exists or not.

Upon each request you would verify the cookie with

This should only work with browser cookies, i.e. the ones that get removed when the browser closes. If this was a persistent cookie it would not work. Once again, this is still experimental, come to think about it, I probably should not have included it here yet, but I might as well and get some feedback on it.

Proper Error Handling

You might ask yourself “Why worry about error handling?”, but have you had a proper look at the information that is displayed when a ColdFusion error is thrown? It could give malicious users information like; configuration, the physical location of the application, datasource name, database tables, and maybe even usernames and passwords plus much more information that is very valuable to someone trying to do harm.

On a production machine you should prevent any debugging from being displayed, and to save resources you should probably turn any type of debugging completely off through the ColdFusion administrator panel.

Use an Error handler in your application that catches all errors, notifies you of the error, logs the error and displays a nice message to the user instead of a white page with stuff they cannot understand. Try and keep the message as simple as possible, on .au we try and make it a little fun, and the heading of our page is “Oops!”

Oops, there was a problem!

The problem could be caused by a network, database, programming (we're only human) or connection problem, you could try again to see if the problem is solved.

The technical team (support@.au) has been notified of the problem and will work on fixing this issue as soon as possible.

A reference number for this problem is [reference number here]

Additional information

Following is some additional information that might be helpful.

You are signed in as #session.User.getScreenName()#

You are not signed in.

You do not have JavaScript enabled.

document.write( 'You have JavaScript enabled.' );

document.getElementById( 'javascript-enabled' ).style.display = 'none';

You accept cookies.

You do not accept cookies, you should know that this site requires cookies to be enabled.

Your IP address is #cgi.remote_addr#

Your reverse DNS is #request.reverseDNS()#

The above information gives the user confidence that the error is being looked at, and the information displayed would help you debug the error if you were speaking to the client on the phone. It might be that they do not have cookies or JavaScript enabled, the output above would give you that information.

Following will give you some idea on how to setup error handlers in your application.

If you are on ColdFusion MX7 or higher you would use the onError event handler in the application.cfc

Note that the output is set to true, because you will be displaying HTML to the user upon an error.

Between the function tags you would have a cfmail to notify you of the error and email any information about the error itself. You would also include the HTML to display to the user with the friendly error message. And last but not least, make sure we are adhering to the internet rules and return a 500 status error.

In ColdFusion MX6 you would be using the tag to include an error template that performs the same actions described above.

Input Validation

You cannot rely on your users to always understand what they need to enter in your form fields, sometimes they make a mistake, don’t understand or are trying to break your system and enter characters that you would not be expecting.

For example, you are expecting a date in your field like “05/11/72” but someone writes “5 Nov 1972”, or a malicious user inputs “my name” in a first name field.

Perform client side validation with JavaScript should only be considered a nice feature to make life easier for your users, it should never be seen as a final solution for data validation. JavaScript can be turned off in the browser and bypassed with ease. ColdFusion Server-side validation is the only way to really be sure that you are able to validate the data.

What can happen if you don’t validate your data? You can end up with a messy database full of information that is worth nothing, it can crash your application, or worse, a malicious user could insert nasty tags that could grab people’s cookies and they could hijack their session.

ColdFusion now has some great tags that can handle the validation for you, but I’ve stuck with the old school and like to have full control with Regular Expressions.

If you are expecting an integer you can use the ColdFusion function val()

When you expect alphanumeric characters and spaces only, you could use the following regular expression

The above basically means; replace everything BUT characters from A to Z, numbers from 0 to 9 and a space. You can get pretty fancy with Regular Expressions and also start checking the format of a string etc.

Securing Protected Areas

Securing a protected area might sound easy to do, but here are some other things to consider;

- have your username and password posted to a page under SSL

- hash passwords in the database so that even if the database is compromised, no passwords can be retrieved, this also protects the passwords against snooping employees

- destroy all session variables upon sign out

- use a session time-out

- log all sign in events and deny access to someone when they have many unsuccessful sign in attempts

SSL

To make sure the page you post the username and password for sing in to is under SSL you can put the following ColdFusion code on the page that accepts the sign in details.

The above code would redirect the user to an SSL page.

Hashed passwords

When you work with hashed passwords, you’ll need to start with inserting a hashed version of the password chosen by the user. When the user signs up and picks a password you would use the following code to create a hash of the password and insert it into the database;

variables.hashedPassword = hash( form.password & "stringonlyknownbyme" );

Someone who chose the password “test” will end up with the following hash in the database

79D2F01DE1937C0D6D9608C7026DD8FA

After you stored the hash, you never have to deal with the real password again.

To check if the user entered the right password when trying to sign in, you would use the following ColdFusion code.

variables.hashedPassword = hash( getPassword() & application.seed );

SELECT myIdentity

, username

, password

FROM tbl_user

WHERE ( username = )

AND ( password = )

if ( rsLoginCheck.recordCount neq 0

and rsLoginCheck.username is form.username

and rsLoginCheck.password is variables.hashedPassword )

{

// handle logic here to do whatever needs to be done for a successful sign in

}

else

{

errorMessage = "oops! Those aren’t the right sign in details. Please try again";

}

Destroy session variables

To destroy all session variables set during the session you would use the following code;

structDelete( session, "user" );

Replace “user” with the session variable you’ve set.

Session time-out

Use a session time out that’s not to high, 20 or 30 minutes will usually do. Setting the time-out high will not only consume unnecessary resources on the server, but it also give malicious users more time to try and gain access to a session that has not been destroyed.

Form being submitted outside of your domain

It is very easy for a malicious user to write a script that submits form values to your website. They might do this to submit SPAM, create fake accounts or plenty of other reasons. You can prevent this from happening, or at least make things more difficult by checking for a referrer in the headers, you do this as following;

We use a Regular Expression here, because if you would use “contains”, the malicious user might be smart enough to put your domain in the referrer through a query string. The malicious user could create a link on their site with the following string in the URL ?somedomain=http::// and when clicked it would activate the script. Obviously the referrer would contain your domain, but would not be at the start of the string, which is what the Regular Expression checks for.

Automated data mining

Someone data mining your site could cost you bandwidth, crash your application, and possibly your reputation if they post the information elsewhere.

One way to make life harder for someone trying to data mine your site, is by hashing the identities of the records you are hosting. Let’s say you have a website that displays classifieds, and you want to make sure that no one can easily data mine the classifieds.

Let’s say a URL to display a classified is

It would be easy to write a cfloop from 1 to 100000 and make a cfhttp request in between and then use cffile to write the content to disk. Perform any actions on the data later.

An easy way to prevent this would be to use a hash of the classifiedIdentity, turning your URL into



In your classified.cfm page you would implement the following code to check the hash

There are obviously many more ways to prevent automated data mining, the above is just one example.

................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download