Monday, June 25, 2007

Security design brain teaser.

Since there is a lot of concern now about how to protect personally identifiable information in our networks, I thought I would pose a question to the community. What is the best way to protect this information in our coldFusion apps. The information I think we should be concerned about the most would be anything that could be used to compromise somebody's identity. That would include names, addresses, phone numbers, social security numbers, bank account numbers, credit card info, etc. I wouldn't include passwords in the group because they can always just be hashed.

For the rest of the list, most companies don't have a need to store the bulk of that information, but certainly names/address combinations are very common. Should that be stored in your database in an encrypted state? For eCommerce companies, the obvious encryption candidate would be the credit card information. Whatever you need to encrypt, the general strategy can pretty much be the same.

Here are three thoughts I've had about protecting this type of data:

1. Utilize the CF encryption functions that now support AES whenever storing or retrieving sensitive data. This is probably the easiest method for me, but I think it suffers from a few drawbacks. The first being that your key would be stored in your cf code. If the webserver is compromised, your password can be easily discovered. Second is that if a brute-force attack is made against your application successfully, the key is retrieved for the entire db. That seems risky to me.

2. Utilize the stored procedure and encryption capabilities of your database. MSSQL2005 and MySQL 5.x+ both include AES encryption functions. For MSSQL2000, you'd have to buy an add-on product. In this case, you would write stored procedures to handle reading and writing sensitive data that encrypted/decrypted data as necessary between the db and your user interface. I think this is quite a bit better than option 1 because we tend to protect our db servers better. Most likely, the db server will not be exposed to the web directly. The one area where this is the same as option 1 is that a single key is being used to encrypt/decrypt your data. Key rotation processes could be introduced at the db level, but they will probably cause some downtime while data is decrypted and re-encrypted with the new key. While that will narrow the window of opportunity, it still puts the db at risk of being compromised with a single key crack.

3. The last idea I had was to use a separate key, like a uuid, for each record and create a new db to act as a keystore. The benefit to doing something like this is that you can put very tight security on the keystore. There also would be no hint of how you are encrypting your data unless you were to have your stored proc code discovered (of course it would be vulnerable to certain insiders). You could also introduce key rotation procedures with this method. What I'm really worried about here is if at this point you're beginning to get diminishing returns. Are we starting to degrade our performance too much to justify the increase in difficulty to crack?

Any thoughts? Is there a developing industry standard for handling this type of information because of Sarbanes/Oxley concerns? What approach are you using?

Wednesday, June 13, 2007

Obscure cf8 error message

While doing some work on a project that is currently running on cfmx, but which I'm testing on cf8, this strange error message appeared:

coldfusion.compiler.ASTsimpleVariableReference cannot be cast to java.lang.String

If you get this message, it's basically telling you that somewhere you've passed a variable or object where a string was expected. In my case, it was with a code bug that the previous versions of cf worked with but probably should have thrown an error. What I found was an indexed loop tag with a variable being used for the index. If you think about it, that really doesn't make sense. I don't think the author meant that the actual variable name would change as the loop executed or that it needed to change based on some value passed in.

BAD
<cfloop from="1" to="#upperLimit#" index="#myIndex#">

Good
<cfloop from="1" to="#upperLimit#" index="myIndex">

What lead me to look at the loop was the stack trace that came along with the error. I don't know if anything else will cause this error, but the variable for an index string will cause it every time.