Showing posts with label security. Show all posts
Showing posts with label security. Show all posts

Tuesday, October 23, 2007

Rant: Rails Lacks Accessor Bottlenecks

Being a longtime user of (and zealot for) Ruby, I have a made a name around the office for my unusually strong understanding of its details. Thus my employers decided that, out of our team of developers, I should be the one to write the security sub-layer for our Ruby on Rails based chiropractic applications (as it would require digging into, and understanding the internals of Rails.

Now before I proceed to beat Rails around a littl bit, I don't want you to get me wrong. I love using Ruby on Rails and would easily chooose to do this project (and future projects) in it again, but sometimes I find some of their design decisions to be, well, web-developerish, while we need a more robust enterprise-developerish solution.

A Bottle With Too Many Openings Can't Hold Water

One of the design patterns that I have seen over and over again in Object Oriented APIs is the use of bottle-necking. That is to say, even within your own class, you choose to use a set of accessors to get at instance variables instead of poking at them directly.

The big benefits to this approach are two fold: It allows you to be more agile with changes (as you only have edit the accessors to change behavior), and it allows third part developers to easily augment or override the default behavior of your code.

An simple example of this may be a simple vector class that stores a magnitude and an angle. Now this angle, in all reality, needs to be between 0 and 360 degrees. So if you have two ways to set this data (from rectangular or polar coordinates), you would have to enforce these limits, probably by using a modulus operator. (Which isn't very DRY, now is it?) But what happens when you have to change the behavior? Maybe the angle needs to be stored in radians, maybe the range needs to be changed to -90 to 90, or maybe it needs to be compass oriented instead of right-handed-axis oriented? Or maybe you just want to add a way to set the angle without changing the magnitude?

All of these requires refactoring your code, which requires duplicating and/or altering your code in several locations! But if you were to make a single accessor for getting, and a single accessor for setting the internal value, then all your other code could go through this accessor (including possible intermediate accessors) to enable fast, agile, and DRY code changes!

Playing With Steam Engines

So, now, let's imagine your employer gives you the spec that your enterprise Rails driven software must have a security system where you can restrict read and write ability to different models, on a per attribute basis. This is what I faced over a year ago.

The way I really wanted to solve this was to override the accessors to the basic hash that stores, as key/value pairs, all the data for the table row the objects represents. That way I could add my own code that would allow or deny access at this fundamental level.

Unfortunately this basic and simple idea (based on past experience with other APIs) exploded in my face. You see, the @attributes hash instance variable that ActiveRecord uses to store these key/value pairs is directly poked and prodded by many separate methods throughout the ActiveRecord class. Thus I had to override all of these methods, making them call the same friggin security check method, to decide if they could continue onto their default implementation or if I should restrict access. (I'm only lucky that the runtime generated accessors utilized standard accessors, or else I'd be re-writing the code-generation routines as well.)

Of course, all this work meant that besides sinking a lot of the company's time and money into implementing a task that should have been simple, maintaining our release against newer versions of Rails is more costly because of all the hacks I've had to do to meet the requirements.

Which is why I'm so peeved at their code. If only they had followed good design practices and bottle-necked all calls to @attributes through a read and write accessor method, it would have been easy to implement customized behavior at this point in the program flow, and thus would have made my security requirements a trivial task.

Friday, October 12, 2007

Article: Security Words

Ever since I've been a kid, I've been fascinated with codes and cryptography. Of course, this topic has some great overlap with security, such as solving problems with storing, retrieving, and comparing passwords. So I was the obvious choice to implement the security engines for the software at the small start-up company that I work for.

Now this article is NOT about implementing security in Rails. This is a big and complicated topic that I do plan on writing about because implementing enterprise level security in Rails is not easy at all.

No, this is about another common topic. We often have to reset passwords for users. (We, of course, only store the hashed form of the password with salt so that no one get them!)

Now most of the time, assigned passwords are generated out of random sets of characters. This is great. A randomly generated password is very secure. But it is really hard to remember.

So I got to thinking. What if instead of passwords, we used a passphrase? That is to say, instead of joining together a series of individual characters, what if we joined together a fewer number of words? For me, at least, it is easier to remember a series of words than random characters, as I can come up with some visual or some rhyme to help me remember it.

For example, most sys-admins might give you a random password that looks something like 2qLzj94k. But what if, instead, they gave you a password like GreenRunDallasOrchard? I'd be willing to bet that you'd be much more likely to remember the 4 words better than the 8 random letters.

But this gives rise to the question: How many words would I need to string together, and from a dictionary how large, in order to match the security of a random string of characters?

Now For The Math

If you hate math, you may want to skim this section. Though I am pretty sure that if you are still actually reading this, then either you are a technical individual and like math, or you are a manager who was forced to read this by your IT staff because you just don't get it.

Normal passwords can be generated using all the letters (uppercase, and lower), digits, and a plethora of symbols. Looking at an ASCII table, it looks like there are, 94 eligible characters that one could use in a password.

Strangely enough, though, most random passwords are generated just with a subset of all letters and numbers, giving only 62 possible symbols. This reduction of 32 symbols leads to a drop of 5,877,349,279,825,920 passwords from all the possible 8 character passwords, which is a reduction in passwords of about 1/28th the fully possible 6,095,689,385,410,816!

Now to calculate the number of random passwords possible with just letters and numbers given password of a given length, we just raise 62 to the power of that length. Thus the following table hilights the number of possible passwords that exist with lengths of 4, 6, 8, and 16.


Password
Length
Possible
Passwords
462414776336
662656800235584
8628218340105584896
16621647672401706823533450263330816
Possible Passwords Composed of Letters and Numbers

So the real question then becomes: If we had a pass-phrase of 4 words, how many words would have to be in our dictionary of random words to match the security of a random string of letters and numbers of a given length?

To calculate this, it is just a matter of the reverse problem from above. We know how many passwords we want there to be, and we know the length needs to be 4, so we use some n-th roots to produce the following table:


Password
Length
Dictionary
Size
4624/462
6626/4489
8628/43844
166216/414776336
Dictionary Size Needed For 4 Word Passphrases to Match Passwords of a Given Length

The Answer For The Math Weenies

So what do all those numbers mean? They mean that to reach the security of a randomly generated 8-character password generated just of letters and numbers, we only need to pull four random words from a dictionary of 3844 words, which is a completely reasonable feat.

Indeed, doing a quick
grep -Ec "^[a-z]{3,6}$" /usr/share/dict/words
on my OS X box seems to indicate that there are 29,041 words, none of which are proper nouns, that are from 3 to 6 letters long that could be used. And expanding the list to contain proper nouns results in a dictionary of 33,925 possible words.

Thus with a dictionary of 30,000 words, it would be possible to match the security of a random 10 letter password made of letters and numbers, with only a four word passphrase! And if we increased the number of words in the passphrase to five, it would add 24,299,190,000,000,000,000,000 passphrases, which is the same security level as a 15 character alphanumeric password!