CF: cflock

CFLOCK is used whenever there’s a chance that more than one process will try to manipulate a given resource at the same exact time. You might use cflock with a database so that if a read operation occurs during a write, the read operation will have to wait for the write to finish. That way the read operation will have the most up-to-date information possible. Normally you don’t need to worry about stuff like this. I use this in a room selection application (where students can pick the room they live in for the following year). I cflock an entire block of logic that first checks to see if the room being selected is available and, if it is, record the room selection. This way I don’t risk someone else selecting the room between the read to check for availability and the write to record the selection. If I didn’t do that, there’s a chance rooms could become double-booked.

When working with a file that is used in an application, you almost always use cflock. Now I don’t mean you cflock whenever someone is uploading a file or you’re going to read from some random htm file (like a template system) because your application isn’t going to be altering the file’s contents (more than once, in the case of writing an uploaded file). But if you’ve got a file your application is going to read and write to throughout the application’s life, you need to protect against the chance two writes will occur at the same time. For example, in a user account claim application I have to write usernames to two separate files. One gets picked up by a process that creates e-mail accounts, another that creates LMS accounts. There’s a chance two people will try to claim an account at the same time. So I’ll cflock the file during the write, so no other CF process tries to write to the file at the same time. If that happened, you can wind up with a corrupt or empty file. Guestbooks, blog comments, etc are examples of applications where you’d cflock file access (assuming you’re using files and not a database).

Now why CFLOCK session variables?

Because you can’t assume a user will only make one connection at a time. When a user requests a page, the web browser begins to make several simulatneous connections to download the images, CSS files, javascript, etc.. on top of the HTML for the page. If you’ve got one or more of those files setup as a CFM (a dynamic image, dynamic stylesheet, who knows what) you’re application.cfm will run as well. If you’ve got logic in your application.cfm that manipulates session variables, you run the risk of having your session variables being changed in mid-process, creating either corrupted data (less likely) or incorrect data being acted upon (more likely).

For example, let’s say you’ve got a voting system. The voting system uses a session variable to set whether or not you’ve voted. A person logs into this system, makes their vote selection, and double-clicks the “vote” button. Your CF server now has 2 separate vote processes from the same person that it will process. The application logic is:

1. Check if allowed to vote
2. Record vote
3. Flag user as having voted

Step 2 is a database operation. In computer time, that step is going to take forever to process. While process 1 is working on step 2, process 2 comes along and passes the check in step 1, and gets in line for step 2. Process 1 moves on to step three and records the user has voted, but only after process 2 has started recording the vote for a second time.

Your user has now voted twice because of a race condidtion with session variables.

To fix this process you can do a couple things. You could put all three steps inside a single cflock block. You could swap steps 2 and 3 and then put steps 1 & 2 (check/record allowed to vote flag) then do your database options. The latter option frees the lock sooner to help keep resources to a minimum and is a potential speed increase but you might lose votes. You could wrap the database operation in a cftry/catch block and reset the flag if needed, but now you’re getting overly complicated in a system where just wrapping the 3 steps in a cfblock works fine.

So why not wrap every page in a cflock?

Because you will have pages that take a few seconds to process. If a user double-clicks a button, like in the example above, they will have to wait twice as long for the results to be displayed. If they get bored/angry at the wait, they might press that button 10 or 20 more times thinking it’ll go quicker, when in reality it’s only slowing things down. At that point, you’ve got 20+ processes waiting for that lock to open up. CFMX recommends your number of simultaneous processes allowed in CF be 3 or 4 times the number of CPUs in the machine. I’ll tell you that we have ours set to 12. (3 * 4 (2 P4s, each of which act like 2 separate processors)). So at 20+ processes, each waiting for that lock, each on the stack of running processes, you’re entire site (or your CF applications at least) grind to a halt. Now every user (not just the one) starts clicking on that button to speed things up. You eventually wind up with a really nasty situation where you’ve got hundreds (even thousands) of processes in the queue waiting to be processed by CF. Your site becomes unusable for minutes, maybe even hours.

That’s why you need to be very very efficient in your use of cflock. They can be a source of severe bottlenecking. I have a cf_sleep custom tag that gets CF to hang for a few seconds. I don’t use it much (if ever) but the way it works is by nesting cflocks on the same resource. Create a page with a 20 second sleep, reload it 20 times, and you’ll shut down the site for 20+ seconds. Very nasty.

If you can, set yourself up with a performance monitor (this is a Windows thing. start->run->perfmon) set on your CF server and you can see this in action yourself. (Assuming you’re setup, monitoring all the CF related monitors.) Turn on highlighting in your performance monitor (CTRL+H or click the lightbulb icon in the top toolbar). Then select the “running requests” monitor from the list in the bottom section of the performance monitor window. The highlighted (white) line you see shows you how many current requests are being processed.

Create a script with a 20 second sleep in it. Load the page then check your performance monitor and you’ll see that there is 1 process running. Now hold down CTRL+R in your browser for a few seconds. You’ll get maybe a couple hundred of these processes going. Now check out the performance monitor. The running requests will max out at 12 (which is what I set it to as mentioned earlier). Now check out the “queued requests” monitor and see how that spikes up.

The site is essentially useless while you wait for those processes to finish. All this because of 1 user holding down CTRL+R in a browser for a few seconds. That’s the downside of cflock (and any slow ColdFusion page). Try changing the page so the sleep is only a second and do it again. The server takes a little longer to go unresponsive, and it recovers more quickly. But you start to see how CF can be exploited.

There’s a configuration option to kill any process that runs over X seconds long in the administrator interface. That offers some protection from prolonged denial-of-service attacks, but not much. (I typically set it to 30 seconds, but 5-10 seconds might be better for most people.)

Increase the number of simultaneous requests? That only prolongs the inevitable and when you hit that max, it takes much longer to recover because your server is doing a lot more than it can handle.

So be careful of bottlenecks in your CF code, CFLOCK being potentially one of the biggest in your application.

CF: Session Hijacking

ColdFusion uses two unique values to keep track of user session information. These values are CFID and CFTOKEN. They are stored as cookies but can also be passed along the URL and inside POST data.

Session variables are a place to store information specific to the user and to the current session (such as whether or not a user is logged in).

It is possible to hijack a user’s session by supplying the correct CFID and CFTOKEN values to the server, either on the URL, or wherever else you want.

The two numbers combined represent a space of 10^15 numbers. Average brute force will take half that amount, so 10^15/2. Figure 100 attempts per second, and the average time it would take to brute force is in the neighborhood of 150,000 years.

There’s the 1 in a jillion chance someone might guess a correct CFID and CFTOKEN, but that doesn’t really worry me much.

Your more likely to see someone hack your application by doing a little packet sniffing (or looking over someone’s shoulder) and capturing the CFID and CFTOKEN that way.

Packet sniffing you can curb by going over SSL with your application. Over-the-shoulder attacks can be stopped by not passing the CFID and CFTOKEN values on the URL (which CF does with cflocation tag by default… go figure).

If the user has a virus on their machine passing out their cookies, well that user has a bigger problem than having their session hijacked.

So how do you protect against session hijacking? You store the IP address as a session variable. Compare the IP in the session variable to the user’s IP (stored in cgi.remote_addr) and if they don’t match, you’ve got a hijacking attempt.

… But there’s a catch.

AOL, for example, uses a proxy server for their packaged browser. This means everyone comes from the same IP address. Not cool. Now AOL users can simply go into their browser settings and kill the proxy config and they’ll surf using their own IP, but can you really ask users to do that for every little application we have using session variables?

Also AOL users won’t be the only ones behind a proxy server.

And if you have session timeouts set to days, dial-up users and any other user on a network with shared IP addresses will eventually get an IP address of a former user. And they might be able to get into the application that way.

So what can you do? Not much. You won’t ever be 100% certain in your security. It’s all about managing risk. In this case, you’re at a fairly low risk with hijacking if you’re comparing IP addresses.

But here’s what I do to take it 1 step further.

Combine the user’s IP address and browser string (cgi.http_user_agent) into a single string. Then MD5 hash the thing. Store that hash as a session variable. Recalculate and compare hashes as the first step in any user request (in other words: put this logic in your application.cfm file, and put it up at the top). And that should protect you well enough. The browser string provides a little extra security in the event of proxy users hitting the site.

Also keep your session timeouts to a low value (30minutes.. 2 hours MAX, unless security isn’t a big issue for your application).

When you detect a hijack attempt, you might not want to kill the session because the legit user also gets locked out. You can reset CFID and CFTOKEN on the user with the CFCOOKIE tag then redirect the user to the enterance page.

ColdFusion

I’ve written some long-winded e-mails about CF development recently and, rather than see them go to waste, I figured I would put them here and have my blog serve not only CSS matters, but CF as well. I’ll put these entries into their own category for those who care to follow.