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.


In reply to Orthogonal Code and Security by Ovid

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.