Securing Your XML Config Files

Yesterday I rolled out a new site, http://www.blitztweets.com. I announced it on Twitter, a few folks retweeted (thanks!), and Ray Camden descended upon it like a vulture descends upon a wounded bunny in the high noon desert heat. Ray’s got a knack for finding flaws in CF sites, and I’d be lying if I said I didn’t have him in mind during development.

Overall, I think I did pretty well. He found two issues. First, my contact form could be submitted without the user filling in any fields. That was OK. I don’t particularly mind if somebody really wants to send me an empty contact form. But the second issue… ooh, that was a doozy, and I’m duly embarrassed by it. He linked me to http://www.blitztweets.com/config/ColdSpring.xml, which proceeded to display the entire contents of the file in my browser window (it’s since been fixed). Oops.

The site is built in Model-Glue 3, and is my first MG3 site. If memory serves, in Model-Glue 2, both the ModelGlue.xml and ColdSpring.xml were renamed with a .cfm extension. My first thought was to apply this same “fix” to the current site, but as Ray pointed out, the files would still be browseable. With that in mind, I set out to figure out the “best way” to secure the XML config files.

In my search, I noticed a couple of things. First, I was surprised that there wasn’t more information out there on how to do this (or maybe I just suck at Google). Given the number of people that use any of the frameworks that make use of XML files, I’d have thought this would be a more popular topic. Second… like so many other things in this field, there is no “one true way”.

I’ll go over a few of the methods that I found, and describe the pros and cons (as I see them) for each.

  1. Rename the .xml files with an .xml.cfm extension

    This is undoubtedly one of the quickest fixes. But if somebody knows the path to your document they can still browse it. You can get around this by sticking an Application.cfm into your config directory with a <cfabort />. This method works, and I think a few of the popular CF frameworks make use of this security model out-of-the-box. While it works fine, there was something about it that just felt “hacky” to me. I’m not quite sure what it was, but I wanted to continue the search.

  2. Moving the config files out of the webroot and using ColdFusion mappings

    This was the first avenue that I explored, as suggested by Scott Stroz. I moved both of the XML files (ColdSpring.xml and ModelGlue.xml) out of the webroot and deleted the config folder. In my Application.cfc, I created a mapping to the new (not in the webroot) config folder. The path to ColdSpring.xml is defined in index.cfm, so I updated that to use the new mapping.

    The path to ModelGlue.xml is defined in ColdSpring.xml. At first, I thought this was going to be a deal-breaker as I didn’t think an XML file would recognize a ColdFusion mapping. However, both Todd Sharp and Jon Messer correctly pointed out that Model-Glue doesn’t just import/read the XML file, it actually parses it, and it will recognize and respect the ColdFusion mapping.

    My concern about this method is that the mapped path to the config folder is different on my development environment (OS X) than it is on my production box (Windows). This is easily handled with a conditional in the Application.cfc where I set the mapping (using cgi.http_host to determine the environment).

    While this worked, I still wasn’t quite comfortable with it. If I moved the location of the out-of-webroot config files, I’d have to remember to update the mapping. Not having all of the files together was also somewhat of a paradigm shift for me. I know there are people who rely heavily on mappings and don’t put anything but view files in the webroot, and that’s probably a model I should look into more… but for now, it was a little outside of my comfort zone.

  3. Apache to the rescue

    I started using Apache on my development box back when I was on Windows. IIS (on non-server OS’s) only allowed one (active) site at any given time, and switching sites was a pain. My current production server is a VPS that’s also running Apache.

    In my VirtualHosts directive for blitztweets, I added a new <Directory> directive that controlled my config directory (which was now back in the webroot). Inside I added:

    Order deny,allow
    Deny from all
    

    Upon browsing to the ColdSpring.xml file, I was greeted with the message, “You are not authorized to view this file”. Perfect. Almost.

    As far as I was concerned, it was OK that people knew they weren’t authorized to view the file, but I’d prefer that they don’t even know the file is there. Quick change to the <Directory> directive:

    Redirect / /index.cfm/
    

    This redirects the user to a non-existent Model-Glue event, which triggers my existing “missing event” error handler, and is the method that I ultimately settled on.

I’m sure there are probably several other creative ways to accomplish this (for example, Todd had mentioned he uses IIS to set a non-browseable permission on the config folder). Any of the above methods will work as well. Like so many other things, it’s just a matter of finding which one feels most comfortable for you.