scollyer has asked for the wisdom of the Perl Monks concerning the following question:

I have a mod_perl handler that I wrote some time ago that I'm now reviewing from the POV of security. It starts roughly like this:
sub handler { my $r = shift; local ($NS::IP_address, %NS::params, %NS::cookies); . . $NS::IP_address = $r->connection()->remote_ip(); . . }
i.e. it localizes some variables in a namespace and then assigns to them, making them globally available throughout the handler.

At the end of the handler, my reasoning was that the dynamic scoping of those variables would ensure that their contents are no longer available to any later request. However, given that those some of those variables contain sensitive data (usernames and password (hashes)), I'd like to be sure that I'm not missing some obvious reason why this could fail in a mod_perl environment.

Any mod_perl gurus out there who can give a definitive yay-or-nay to my approach above ?

Steve Collyer

Replies are listed 'Best First'.
Re: mod_perl: globals and security question
by ikegami (Patriarch) on Oct 12, 2005 at 14:49 UTC

    That looks great to me, since local will restore the value even if handler exits due to an exception (die). My only concern would be threads. I don't know how Perl shares variables between threads, and I don't know how mod_perl works in a multi-threaded Apache.

    By the way, you can save yourself some typing by using our. The following code is equivalent to your code, but saves you from typing "NS::" every time you reference these variables:

    our ( $IP_address, %params, %cookies ); sub handler { my $r = shift; local ( $IP_address, %params, %cookies ); . . $IP_address = $r->connection()->remote_ip(); . . }
      >That looks great to me, since local will restore the value
      >even if handler exits due to an exception (die).

      That's what I'd hope, but I feel the need to get the reassurance that it won't fail mysteriously in mod_perl land.

      >By the way, you can save yourself some typing by using our.

      Right. Two comments.

      1. I know about our and tend to use it exclusively these days, but at the time I wrote that code, I was too set in my old-fashioned ways.

      2. Although our can save a bit of typing, it also masks the fact that, say, IP_address, *is* global, and I'm not yet convinced that that's always a good idea. At least if someone sees a package identifier at the start of a variable, they know for sure that globals are being used, and can factor in the potential long-range effects of altering those variables. In short, if you're going to be Evil, then it may be a good idea to trumpet the fact, rather than hide it away.

      Steve Collyer

Re: mod_perl: globals and security question
by derby (Abbot) on Oct 12, 2005 at 14:00 UTC

    i.e. it localizes some variables in a namespace and then assigns to them, making them globally available throughout the request.

    From the small snippet given, the variables are not available throughout the request but only until the end of the block (in this case the handler). If you need to pass data around the different phases of the request, then pnotes is what you need.

    -derby
      Well spotted - I should have said "available throughout the handler".

      I've corrected the original post. The code works fine, BTW; It's that specific security hole that I'm interested in.

      Steve Collyer

Re: mod_perl: globals and security question
by perrin (Chancellor) on Oct 12, 2005 at 14:33 UTC
    I don't see any security problem from this, but it's a bit strange. Are you trying to accomodate some legacy code? There aren't many reasons to use local anymore.
      There aren't many, but one of them is to temporarily assign a value to a global. That's what the OP wants, so it's not strange at all. One of the reasons it's not used much anymore is because the use of globals is discouraged. That doesn't mean there are times where the advantages of using globals outweigh the disadvantages. This appears to be one of them.
        That's why I was asking if this was in support of legacy code. Most cases where this used to be needed would be handled with lexicals these days, so they are mostly reserved for things like $/. There are other ways to do what the OP is after, and I think they would probably be less confusing to non-expert Perl coders.
      >I don't see any security problem from this, but it's a bit
      >strange. Are you trying to accomodate some legacy code?
      >There aren't many reasons to use local anymore.

      I'm not sure what you see as strange: the use of globals in general, or the use of local ?

      Regardless:

      Q1. Why am I using globals at all; aren't globals evil ?

      A1. The code in question is part of some authentication/access control logic which runs structurally identical code in both CGI and mod_perl environments. This means that there's only one code base to make fixes in, add features to, review for security issues, etc. (And that's a GoodThing(tm)).

      To simplify the task of writing the code in a mod_perl/CGI independent fashion, I make certain data available via a small number of globals. (There may be a cleaner solution, but I couldn't see one at the time I was writing it).

      So globals may be evil, but in this case, they simplified things sufficiently that I'm happy to live with the shame and debasement of my soul.

      Q2. Why are globals localized ?

      A2. Because globals are potentially evil, in that if one isn't too careful, in the wrong environment, (mod_perl perhaps) their contents may persist for longer than one would wish (and perhaps expose usernames, cookies, etc to another handler). So to mitigate this problem, they've been localized to the dynamic scope of the handler routine, and thus we can (I hope) rely on Perl to undef them at the end of the handler (but leaving them usefully available while the handler is executing)

      Does that help ?

      Steve Collyer

        That does make more sense. I generally put that stuff in %ENV, so that both of them can read it. The environment variables don't persist between requests in mod_perl. Alternatively, I sometimes make a simple fetch/store API which uses $r->pnotes() under mod_perl and globals under CGI. (Hmm, possible CPAN module?)