develooper Front page | perl.libwww | Postings from February 2001

Disabling protocols in LWP (was: security problem withLWP::Simple::get in CGI scripts)

Thread Previous
From:
Sean M. Burke
Date:
February 8, 2001 12:45
Subject:
Disabling protocols in LWP (was: security problem withLWP::Simple::get in CGI scripts)
Message ID:
3.0.6.32.20010208132708.00890370@mail.spinn.net
At 09:46 PM 2001-01-29 +0200, Jukka Suomela wrote:
>[...pointing out a potential for evil...]
>        HTTP/1.0 302 Foobar
>        Location: file:///etc/passwd
>
>LWP gets back the redirection and honors it.  It opens the local file now
>and sends its contents to the evil user.[...]

I got to thinking about this and have decided that there are many
conditions under which I'd want a given program to not honor a any
"file:..." URL.

So I started digging around in the parts of LWP that most people don't see
(but which are, incidentally, quite tidily documented), and found that one
can specify what class should handles requests for a given URL scheme (like
gopher:, http:, https:, file:, etc.).
By simply making a class that "handles" requests by refusing them, and then
designating that as the handler for whatever scheme you want to disable,
you can restrict things however you like:

{
  package LWP::Protocol::No_go;
   # Class to "implement" any protocols that you want to
   #  actually have disabled.
   # Put this in LWP/Protocol/No_go.pm

  use HTTP::Response ();
  use HTTP::Status ();

  use LWP::Protocol ();
  @ISA = ('LWP::Protocol');

  sub request {
     # You've got the body / Now you want my soul
     #  / Don't even think about it / SAY NO GO.

     HTTP::Response->new(
       &HTTP::Status::RC_NOT_IMPLEMENTED,
         # Or RC_BAD_GATEWAY or RC_FORBIDDEN?  Dunno.
       'All LWP "' . ($_[1]->url->scheme). '"-scheme access disabled'
     );
  }
}

Then to disable 'file://' URLs you just say:
  use LWP::Protocol::No_go;
  LWP::Protocol::implementor('file', 'LWP::Protocol::No_go');


I could even suggest this addition to LWP::Protocol --

sub LWP::Protocol::unimport {
  # "unimport" is what gets called when you say "no modulename ..."
  shift; # ignore the class-name
  foreach my $scheme (@_) {
    require LWP::Protocol::No_go;
    LWP::Protocol::implementor(lc $scheme, 'LWP::Protocol::No_go');
  }
  return;
}

That's so you can say:

no LWP::Protocol qw(file https mailto);
  # or whatever you want to turn off

...which is a compile-time prama that calls LWP::Protocol::unimport with
those parameters.  Granted, that's not any more meaningful than this:

use LWP::Protocol::No_go;
foreach my $x (qw(file https mailto)) {
  LWP::Protocol::implementor($x, 'LWP::Protocol::No_go');
}

but the "no..." form is clear, concise, and pretty.


--
Sean M. Burke  sburke@cpan.org  http://www.spinn.net/~sburke/


Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About