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

Hi Monks!
My question is about security on this sample code I found around one application I am about to work with. If you look and see the regular expression here:

if ($entered_un =~ /^us./i){ $sql = "select name, pass from unpw where name = '$entered_un'"; }


The "." could be a open door to bad stuff, and all the person was trying to match was if at the beginning of the string there was a two letters or three letters character(s), I don't think the "." is needed or to be in a safe side, make the regular expression check more explicitly.
Please any advice? Can you show any sample of the risk passing something to a SQL query by using such code?

Replies are listed 'Best First'.
Re: Secure Regular Expression Check
by moritz (Cardinal) on Sep 09, 2008 at 14:16 UTC
    Your user could provide the string user' OR 1 --, which means that the query always returns all rows in the table.

    A better protection is the usage of placeholders, as demonstrated in the DBI documentation:

    my $query = $dbh->prepare(= "select name, pass from unpw where name = +?"); # no checking needed here: $query->execute($entered_un);
      (Additionally, even if the DBD doesn't support bind variables, the DBI still provides quote(), which will probably do a 100% better job than a hand-rolled regex any day.)

      -Paul

      In danger of going OT, but could not resist the chance to share this picture (commentary is in Spanish but yuo get the idea). It is a number plate with the text  'OR 1=1; -- ...designed to effect a SQL injection attack on ANPR cameras!
        How very cool ;-)

        I assume you also know about Bobby Tables?

Re: Secure Regular Expression Check
by Fletch (Bishop) on Sep 09, 2008 at 14:16 UTC

    That's still trivial to bypass: q{us' or 'x' == 'x}. Better is to use placeholders and not let the SQL parser see user input to begin with.

    Update: Or worse if the database in question allows compound statements, q{us'; drop table unpw; --}

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Secure Regular Expression Check
by planetscape (Chancellor) on Sep 10, 2008 at 07:57 UTC
Re: Secure Regular Expression Check
by Narveson (Chaplain) on Sep 09, 2008 at 14:24 UTC

    Use the regex to untaint the user-entered string:

    my $GOOD_NAME = qr/^(us\w*)/i; my ( $accepted_name ) = $entered_un =~ /$GOOD_NAME/ or die "Unacceptable input: $entered_un"; $sql = "select name, pass from unpw where name = '$accepted_name'";
      $sql = "select name, pass from unpw where name = '$accepted_name'";
      No, please don't recommend that. As Fletch writes above, that's still trivial to bypass. It's far too easy to write a regexp that will slip something unwanted through, which would, when not combined with placeholders or DBI::quote, represent a security risk.

      Use placeholders.

      Update: Revoked statement on triviality.

      --
      No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]