Daily Archives: August 6, 2004

You are browsing the site archives by date.

Canonicalization issues and File Paths

I keep running into code lately that does some pretty elaborate security testing but in the end leaves a very large issue unaddressed — canonicalization errors related to file I/O.

Michael Howard and David LeBlanc dedicated an entire chapter in Writing Secure Codeto the idea that “All Input is Evil“. The concept is that you should not rely on the fact that input coming from any source — trusted or not is going to be in a format that you accept. You should validate, validate, and validate again even if your I/O function isn’t intended to access anything of great importance.

Canonicalization is the process of breaking something down to it’s most simple form. Let’s take a look at an example:

public FileStream OpenFile( string fileName )
{
string fullPath = string.Format(@”C:inetpubwwwroot{0}”, fileName);
return new FileStream(fullPath, FileMode, FileAccess);
}

You may have ony intended to give this function access to code stored in the default web root. But what would happen if someone called your function like this:

File f = OpenFile(”..\..\windows\system32\config\sam”);

The elipsis at the begining of the path would direct the file to go up a directory and doing it twice would put the user at your root directory, giving someone access to your entire file system.

You could use a regular expression to check for this type of thing right? Well, yes, but it wouldn’t be enough. Your regular expression would test for the “..\” sequence, but what happens if someone encodes the path with %2E instead of the “.”. Would your regular expression be smart enough to check for that? Probably not. There are a ton of ways to represent a path differently and you should use many different forms of validation. However, one of my favorite is to use the DirectoryInfo and FileInfo “FullName” property. Creating a new FileInfo instance passing it your intended path will break the path down into it’s actual meaning. Once this is done, you can use the FullName member to obtain the canonicalized path. As a matter of completion, here is some sample code to get you started:

public FileStream OpenFile( string fileName )
{
string fullPath = string.Format(@”C:inetpubwwwroot{0}”, fileName);
string canonicalizedPath = new FileInfo(fullPath).FullName;
return new FileStream(canonicalizedPath, FileMode, FileAccess);
}

Another option available is to use the Path class as follows:

public FileStream OpenFile( string fileName )
{
string fullPath = string.Format(@”C:inetpubwwwroot{0}”, fileName);
string canonicalizedPath = Path.GetFullPath(fullPath);
return new FileStream(canonicalizedPath, FileMode, FileAccess);
}

This performs the same work under the covers without creating a FileInfo instance.

This example does not explain everything that a dilligent coder worried about security should do to secure this method, but it should demonstrate the usefulness of the FullName member in validating file paths.

Universal Identity a Bad Idea

In a day and age when you are either griping about security or banging out articles on how to increase code security, it’s hard to believe what I saw with my own eyes today. A large and well-known website was looking for a developer to create a universal registration and login service much like Microsoft Passport. The specification called for “seamless integration capabilities into any given website.“

On the surface, these types of services seem like a wonderful idea that prevents someone from having to type in their personal data from one site to the next. Instead, the user would click on a “sign in” button very similar to the .NET passport, they would enter their credentials and data you decide to share with a vendor is magically shared with this site. Microsoft passport requires a rather interesting partnering process in order to get passport authentication on your site. This is supposed to prevent malicious sites from just implementing the “sign in” button and taking your data when you don’t know better.

The problem comes with “seamless integration” and forged sites. It should come as no surprise that Microsoft also has methods that allow passport screens to be thrown into your website’s layout making the login process seem more seamless than redirecting to the passport website itself. This is a very dangerous idea, however. Think about the scenario where you find a gadget you just have to have and, guess what, it’s on clearance for 25% off on this site. You decide to “register” on this site by clicking the login button. The familiar login screen pops up and you enter you r login information.

Have you spotted the problem yet? A crafty individual could create this site that has the same look and feel as the login website. Instead of allowing you to log in as you thought you might, the malware could display an error that would have you believe the site just isn’t working at the moment. No big deal, you go to another site and forget all about this site. The problem is that you have already transmitted your username and login information to this site and that information is now in the hands of an identity thief, and gives a stranger access to any site that uses your login information.

I remember watching a movie (I think it was “xXx“ with Vin Diesel) where a guy drives up to valet parking and hands over his keys. The valet then proceeded to steel the guy’s car. When it comes to embedding a universal login “block” into any page, it just isn’t safe. Anyone can mock up the interface and make it look identical to the login pages that you know and trust. Before you realize what you’ve done, you’ve given someone the “keys“ to any site that uses your login. Personally, I don’t use the same password in any two places. I certainly don’t like the idea of logging into a website just because their login block looks like something I trust.

Keep this in mind the next time you hit eBay and click the passport “sign in” button.