| By Michael Smith | Article Rating: |
|
| September 15, 2004 12:00 AM EDT | Reads: |
27,859 |
All data-driven Web sites are potentially vulnerable to hackers, whether they are written in ColdFusion or another language. Fortunately, a few simple steps can make your site much more secure.
1. Have an Error Handler
By default ColdFusion displays a detailed error message when there is a problem in your code. Yes, I know - your code has no bugs in it - but what if a hacker deliberately creates an error by manipulating URL parameters or faking out a form submit? If they can make an error and view the error message, they may see your data source and table names, which could help them create a SQL injection attack (see Tip 6 for more on this). To protect your error messages from prying eyes, add a CFERROR tag in your application.cfm to catch all errors and display a harmless message to users and hackers alike. I also like to e-mail myself a private copy of the error message so that I can either fix it or be warned that a hacker is on my site.
In your application.cfm use:
<cferror type="EXCEPTION" template="error_exception.cfm" mailto="michael@teratech.com">And in your error handler file error_exception.cfm, use this code:
<CFMAIL to="#error.MailTo#" from="info@teratech.com" subject="ColdFusion Error in #error.Template#"> Address: #error.RemoteAddress# Template: #error.Template# Date: #error.DateTime# Message: #error.Diagnostics# </CFMAIL>To be extra careful, trap for the REQUEST type for CFERROR after the EXCEPTION type. This is a backup error handler for sites with high user interface requirements. You might also turn off the setting for showing the full path to error messages in the CF Admin. Neither should you give more information in error messages than you have to. For example, on a logon screen don't say that "the user id is correct but password wrong," because that gives extra information. Just say "logon denied."
2. Prevent Cross-Site Scripting
Cross-site scripting occurs when a hacker changes your URL, FORM, or COOKIE parameters to either create an error or to view unauthorized information. Changing URL parameters is just a matter of editing the URL line in the browser. Changing hidden form fields is a bit harder. Here is how the hackers do it: they save the HTML of your posting page on their server, edit the hidden form fields, edit the FORM ACTION parameter to point to the submit page on your server, and then submit their copy of the posting page from their browser.
In the past this technique has been used to change the price for an online store item from $100 to $1, causing great losses for the Web site. (Of course, it is bad security design to put such data in the form anyway - the less you expose the better.) Fake form submits can also bypass any client-side validation that you are doing on the form fields submitted. What to do? Protect your URL and hidden FORM variables from outside manipulation.
For URL variables you can use the free functions URLEncrypt and URLDecrypt from CFLib (www.cflib.org is a library of ColdFusion functions that you can use in your code). URLEncrypt will let you display your URL variables as one big coded string (like the big URL strings you can see on Amazon.com) and decrypt them on the receiving page back into individual URL variables.
For Form fields, use a Checksum field so you can prevent them from being changed.
In the calling page:
<input type="hidden" name="ID" value ="#GetBouquets.BouquetID#"> <input type="hidden" name ="checksum" value ="#hash(GetBouquets.BouquetID)#">In the submit page:
<CFIF hash(FORM.ID) neq FORM.checksum> Bad Form<CFABORT> </CFIF>The hash() function gives a check sum for a string so if the string is changed, the hash of it will change too. For multiple hidden fields you can first combine them into one string, then hash that. It doesn't matter how long the string is, the hash function always returns 32 characters.
I also suggest that you validate all URL and FORM parameters with the CFPARAM tag. This tag cannot only provide a default value, but it can also check data types. If you want to make sure that a URL parameter is supplied, just leave out the DEFAULT parameter of CFPARAM and an error will be thrown if the URL variable is missing:
<cfparam name = "URL.ID" type = "numeric">3. Remove Dangerous Characters
Some characters can be used by hackers to inject dangerous SQL, HTML, or JavaScript into your site, for example a SCRIPT tag or an onClick event. You can easily prevent these kinds of problems by scanning and removing dangerous characters from all URL and FORM variables in your application.cfm using the REReplaceNoCase() function. Typical characters to remove include: "(", ")", "<", ">", "/", and "|". The SafeText function from CFLib is also useful when you want to allow some HTML but not the dangerous stuff.
4. Prevent Fake Form Submits
As I mentioned in Tip 2, hackers can submit fake forms from their server to your submit pages. To prevent this, check the referrer Web page using the CGI variable CGI. HTTP_REFERER. If it is in the same domain as your site, then all is okay. You can test for this either in each submit page or once in your application.cfm file like this:
<CFIF not (CGI.HTTP_REFERER contains "http://www.mysite.com/")> <CFABORT> </CFIF>Note: Because the CGI.HTTP_REFERER comes from the browser it can be hacked, so the above test will not stop the determined hacker, only the casual one!
It is also a good idea to protect CFINCLUDE and CFMODULE files from being run stand-alone; they may do bad things or generate error messages when run this way. One easy method is to use a common file naming or subdirectory convention for all includes and modules. In the application.cfm test the CGI.script_name to see if it contains this string. The CGI.script_name variable gives you the URL path and filename of the current CFM file being run.
This method is especially important when coding using the Fusebox methodology, because the site structure and certain filenames will be known without seeing your source code. In a Fusebox application only the index.cfm file needs to be run. Here is how you can protect the includes files in this case:
In Application.cfm:
<CFIF CGI.script_name contains "index.cfm"> <!--- ok to run ---> <CFELSE> <CFABORT SHOWERROR="Protected page"> </CFIF>Alternatively, place included files or cfmodule files outside the Web root.
5. Stop Unauthorized Data Mining
As I mentioned in Tip 2, hackers can change the values of URL or FORM parameters to view other people's data. For example, if you have a parameter user ID=5 in your page's URL variables, they might try running the page with user ID=4 to see what data they can see.
Again, the fix is to prevent users from changing sensitive parameters by using checksums or encryption. However, don't get carried away and protect all parameters, because some may be used by other sites linking to you. A classic example is the book ISBN on Amazon's site: most of their URL is one long encrypted string, but the ISBN is left in plain text so that other sites can link to books on Amazon's site.
6. Validate Parameters and Prevent SQL Injection Attacks
One way hackers can hurt your site is by running bad SQL in your queries by typing the extra SQL into URL or FORM parameters that you use in your CFQUERY statements. A little-known feature of SQL Server is that you can run two SQL statements from one CFQUERY by separating them with a semicolon. Hackers exploit this by injecting extra SQL via URL parameters.
For example, suppose you have a CFQUERY in page.cfm that contains the following SQL:
SELECT * FROM EMP WHERE ID = #URL.USER ID#And normally the page is run like this:
http://myserver/page.cfm?USER ID=7This will cause the following SQL to be run in your CFQUERY:
SELECT * FROM EMP WHERE ID=7Now the hacker adds extra SQL commands on the end of the URL variable (the %3B and %20 encode a semicolon and a space, respectively, in a URL string):
http://myserver/page.cfm?USER ID=7%3BDELETE%20FROM%20CustomerTableThis will cause the following SQL to be run in your CFQUERY:
SELECT * FROM EMP WHERE ID=7 ;DELETE FROM CustomerTableThis will run both SQL commands and delete all your records from the table CustomerTable!
Other attacks use the vertical bar character (|) to run VBA functions in Access. One of the most dangerous VBA functions is shell(), which will run any command string in a shell on your server. Just think what a FORMAT command might do to your server! In SQL Server the similar xp_cmdshell function is equally dangerous and can be turned off in the SQL Server admin.
To prevent SQL injection hacking, use <CFQUERYPARAM> on all SQL parameters. If you haven't come across this tag before, it is used to validate the data types of SQL parameters inside CFQUERY tags. Here is an example to make things clearer:
<CFQUERY name="getFirst" DATA SOURCE="cfsnippets"> SELECT * FROM EMP WHERE ID = <CFQUERYPARAM value="# URL.USER ID #" CFSQLType="CF_SQL_integer"> </CFQUERY>In this code the URL.USER ID will only be allowed to be an integer; any hanky-panky with semicolons or bad extra SQL will generate an error (that you can catch, of course). A side benefit of using CFQUERYPARAM is that your queries will run faster because SQL Server or Oracle will be more likely to use a cached query plan instead of recalculating the query plan from scratch.
Note: Some programmers use the ColdFusion val() function to protect numeric parameters, but CFQUERYPARAM also works with other datatypes and - unlike val - it generates an error when the data type is incorrect. Also, the previous tips on removing dangerous characters and encrypting URL variables help to prevent SQL injection attacks, but these should be used only in addition to CFQUERYPARAM, and not instead of it.
7. Use Server-Side Validation to Back Up Client-Side Validation
As I mentioned in Tip 2 on cross-site scripting, fake form submits can be used to remove or modify any client-side validation that you use on your site. While I recommend using client-side validation (such as CFFORM, JavaScript, and _ field name validation) to make the user interface better, I do not rely on it for security. For that purpose I use server-side validation to back up client-side validation. For example, if you have a field that must be a date, use this code on your submit page:
<CFIF isdefined("FORM.MyDate")>
<CFIF not isdate(FORM.MyDate)>
Bad date <CFABORT>
</CFIF>
</CFIF>
Alternatively, you could use the CFPARAM statement:
<CFPARAM NAME="FORM.MyDate" TYPE="date">8. Harden Your Logon Code
You may have password-protected areas of your site for admin or members only. Be sure that the "front door" of your logon screen is strong. For example, require hard passwords from your users, such as ones with more than eight characters and requiring numbers as well as letters. The PasswordCheck function at CFLib can help you with this task by verifying the length and type of characters in a password. And if you need an easy-to-type random password, check out MakePassword at CFLib. It will create a password with random characters without the confusion between lowercase L and the number 1, etc.
Once all your users have strong passwords, consider making them change them every six months to further protect your login. And don't store passwords in your database, in case a hacker gets a copy of your user database. Instead, store the hash of the password instead of plain text by using the hash() function. Here is how to use this in your logon screen:
<CFQUERY NAME="CheckPerson" DATA SOURCE="UserData"> SELECT PasswordHash FROM SecureData WHERE user ID= <CFQUERYPARAM VALUE="#user ID#" CFSQLType="CF_SQL_CHARVAR"> </CFQUERY> <CFIF Hash(Form.Password) IS NOT CheckPerson.PasswordHash> <CFLOCATION URL="unauthenticated.cfm"> <CFELSE> <CFLOCATION URL="authenticated.cfm"> </CFIF>For a really secure login, consider timing out the login for an hour for a particular user ID after three failures at logging in. This prevents hackers from automatically trying thousands of common passwords via an automated submit program.
9. Prevent Timeout Client/Session Backdoors
When you are using client or session variables to protect secure areas of your site there is still the problem of your users leaving their machines logged in while they go to lunch. A hacker could see the open browser and steal confidential data. For this reason it is wise to use a short timeout of 10 minutes.
Normally I handle this in my code rather than changing how long the session or client variables exist. Partly because it is easy for me to control and customize for each user, but also so that while I log out users automatically, I can still offer them the chance to reenter their password and not lose any data that is stored in their session.
I would also suggest that you make the associated session/client cookies CFID and CFTOKEN automatically delete after the browser closes. Otherwise a hacker may open the browser and use the history feature to go to your secure pages if the user forgot to log out! Here is the code to make CFID and CFTOKEN expire immediately on browser close.
<cfcookie expires="NOW" name="CFID" value="#cookie.cfid#"> <cfcookie expires="NOW" name="CFTOKEN" value="#cookie.cftoken#">This keeps the current cookie names and values but makes sure that they disappear when the browser closes.
10. Avoid Trojan Horse Uploads
Some sites let you upload graphics or other files. If you are not careful, hackers can use this feature to upload program files and then run them from your Web site. Or they might try to overwrite critical system files by using ../ paths. To prevent this, always store uploaded files outside your Web root and strip out any path information from filenames. Also be careful if you use CFCONTENT to display a file where the filename is given via a URL parameter. The page can be misused to send back your source code if a hacker gives the path and name of your CFM files instead of a graphic. Again, storing displayed files outside of the Web root helps, as does validating that the parameter filename does not contain any path such as "../".
What Security Means
Security is difficult because a hacker needs only one window to be open to get in, whereas you must close all the holes. Assume bad things will happen and code for them! Security is a way of thinking: "How can they get into this page?" Finally, realize that more knowledge is power; don't keep security tips secret! The more people who know how to secure their sites the fewer hackers can get in.
Published September 15, 2004 Reads 27,859
Copyright © 2004 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Michael Smith
Michael Smith is president of TeraTech (www.teratech.com/), an
11-year-old Rockville, Maryland-based consulting company that
specializes in ColdFusion, database, and Visual Basic development.
![]() |
Taco Fleur 01/25/08 01:39:34 AM EST | |||
Hi, I just wanted to say, great article. I think that the checking for the referer could be improved upon, as using "contains" can easily be bypassed. Its better to check with a regular expression like so someone smart could put the domain name anywhere in the URL. |
||||
![]() |
Steve Ray 09/16/04 10:14:14 AM EDT | |||
I agree that we need to not only catch our errors, but email them to ourselves (and then provide a friendly error page for the user). The specifics of how to do that or what to include will vary some from one developer to another. For me, I've found that having a lot more info on the error than what I'd get through simply including the offending template, ip address and a couple of other fields is preferable, and can really speed up the process of debugging the error. So, I decided to plop every bit of info I could think of into a struct, and send myself that. It works quite well. Everyone is welcome to grab a copy the UDF (poorly-named ErrorList) from my site (www.delraysteve.com). Happy debugging! |
||||
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Adobe Reader Sued
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Adobe Flex Developer Earns $100K in New York City
- Adobe LiveCycle Enterprise Suite 2 for Cloud Computing
- Adobe Cans Another 9% of its Workforce
- Adobe Betas Target RIAs and Cloud Computing
- Adobe MAX 2009 Online
- Thinking of Flex in London
- Moyea DVD4Web Converter V2.0 Converts DVD to FLV Fast and Synchronously with Watermarks
- Adobe & Salesforce Cut Cloud Deal
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Eval JavaScript in a Global Context
- Fig Leaf Software to Exhibit at Government IT Conference & Expo
- Is Microsoft as Free as Open Source?
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Adobe Reader Sued
- The Planet Named “Bronze Sponsor” of Cloud Computing Expo
- Microsoft Expression Web Has Got Game
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Bruce Chizen Joins Voyager Capital as Venture Partner
- My Top Seven Wishes From Adobe MAX 2009
- Adobe Flex Developer Earns $100K in New York City
- The Next Programming Models, RIAs and Composite Applications
- Where Are RIA Technologies Headed in 2008?
- Constructing an Application with Flash Forms from the Ground Up
- AJAX World RIA Conference & Expo Kicks Off in New York City
- CFEclipse: The Developer's IDE, Eclipse For ColdFusion
- Personal Branding Checklist
- Adobe Flex 2: Advanced DataGrid
- Has the Technology Bounceback Begun?
- Building a Zip Code Proximity Search with ColdFusion
- i-Technology Viewpoint: We Need Not More Frameworks, But Better Programmers
- The Asynchronous CFML Gateway
- Web Services Using ColdFusion and Apache CXF




































