Orthogonal code. You've probably heard of it. You may understand it. If "orthogonal" describes your code, you're a happy programmer -- and so are the programmers who have to maintain your code.
Orthogonal, in this context, means that a change in one place in your code will not affect anything else in your code. Using a car as an analogy, if you step on the brakes, you don't want your car to pull sharply to the right. If you turn on your windshield wipers, your high beams shouldn't come on. Cars are extremely orthogonal to the end user. If they weren't, we'd have many more car crashes.
Your code should also be orthogonal. Isn't it nice to know that to reconfigure many programs, usually you just need to change the config file and restart? I worked on one system that required -- simply to add an item to a pull-down menu -- that I rewrite some Javascript, some Perl code, some SQL, and tweak the database. The Javascript, Perl, and SQL were each in a different file. This, clearly, was a non-orthogonal system. Maintenance was a nightmare and the code was (surprise!), buggy.
So, here I am thinking about orthogonality when Stamp_Guy (whose name is used with permission), was asking me how to securely verify whether or not a user-supplied path is safe to write to from a CGI script. Hmmm... we have a problem here. If there is only one path, the user doesn't need to supply it. Clearly we can have multiple paths. Ordinarily, if I need to do something with a directory, I try to write my code so that it is flexible with its environment. Directory doesn't exist? Create it. Has my program been moved? Maybe I should make directories relative to the program's location. By thinking about these needs, I make my code more orthogonal. When (not 'if') its environment changes, it's not affected.
But what about security and multiple target directories that we need to validate? My thought is to reconsider orthogonality. Here is one case where I don't want my code figuring out what to do on the fly. Why? I don't want to take a chance that either I or another programmer is going to introduce a bug that compromise the security. I would much rather have my program die, or spit out copious error messages than find out that I've been rooted.
First, here's some code that I threw together for this problem:
#!/usr/bin/perl -wT use strict; use CGI qw/:standard/; my %paths = ( '/somepath/data' => '2', '/somepath/data/bob' => '1', '/somepath/data/alice' => '1', '/somepath/data/tom' => '1', '/somepath/config/foo' => '2', '/somepath/config/bar' => '2', '/somepath/config/bar/baz' => '1' ); my $tainted_path = param( 'path' ); # this line will take things like 'foo/bar' or '///fooo///bar' and ret +urn '/foo/bar' # note that all paths are assumed to be absolute. Easier that way. $tainted_path = '/' . join '/', grep { $_ !~ /^\s*$/ } split '/', $tai +nted_path; my $clean_path = ''; # Do not, under any circumstances, change this routine unless # you know exactly what you are doing and why. If you're not # sure why I said that, then you don't know what you're doing if ( exists $paths{ $tainted_path } ) { ( $clean_path ) = ( $tainted_path =~ /^(.*)$/ ); } else { # whups! Can't find it. Here's where we do the error handling } # $clean_path is now untainted and safe to use
Note: the unused hash values are provided in case someone needs "access level" control over the directories.
What's the strength of the above code? It's not possible for the user to enter a path that you do not want him or her to have access to. What's the weakness (aside from the dot star untainting that just gives me the willies)? This code is no longer orthogonal. If we need to add a new directory somewhere, I need to update my code. I could write the directories to a config file and have this (and other programs) read from it. That will make the maintenance a bit easier, but then I'm relying on something outside of the program to ensure security: not good.
I really don't want my code to be a maintenance headache. However, we've heard many times that security and convenience are in inverse relationship to one another. Is this an example? Have I missed a better way of approaching this problem?
Cheers,
Ovid
Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re (tilly) 1: Orthogonal Code and Security
by tilly (Archbishop) on May 02, 2001 at 23:29 UTC | |
|
Re: Orthogonal Code and Security
by Masem (Monsignor) on May 02, 2001 at 22:12 UTC | |
by Ovid (Cardinal) on May 02, 2001 at 22:28 UTC | |
by Masem (Monsignor) on May 02, 2001 at 22:42 UTC | |
by MeowChow (Vicar) on May 02, 2001 at 23:25 UTC | |
by kudra (Vicar) on May 03, 2001 at 12:59 UTC | |
|
Re: Orthogonal Code and Security
by eejack (Hermit) on May 03, 2001 at 07:59 UTC |