Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot

Preventing injection attacks

by Win (Novice)
on Apr 02, 2007 at 13:42 UTC ( #607824=perlquestion: print w/replies, xml ) Need Help??

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

This is an interesting site for any web or database developer. With this in mind I've had a go at screening all input lines into my app with the following:
if ( $_ =~ /$(\#|--|\/\*|\*\/|IF\s|ELSE\s|\s+\s|\s\|\|\s|CONCAT\ +(|\sCHAR(|\sLOAD_FILE\(0x633A5C626F6F742E696E69\)|ASCII()|DELETE\s|DR +OP\s|UPDATE\s|EXEC\s|EXECUTE\s|DECALRE\s|master\.\.sysmessages|master +\.\.sysservers|masters\.\.sysxlogins|sys\.sql_logins|INSERT\s|CREATE\ +s|SELECT\s|MERGE\s|JOIN\s|UNION\s|\sOR\s|\sHAVING\s|\sINTO\s|\sORDER\ +s|\sBY\s|\sSUM\(|\sWHERE\s|SHUTDOWN\s|SUBSTRING\(|NOT\sIN\(|ISNULL\(| +WAIT\sFOR\sDELAY\s|BENCHMARK\(\)|\sTOP\s|MD5\(|SHA1\(|CHAR\(|PASSWORD +\(|ENCODE\(|COMPRESS\(|BENCHMARK\(|ROW_COUNT\(|SCHEMA\(|VERSION\(|xp_ +cmdshell|xp_regread|xp_regaddmultistring|xp_regdeletekey|xp_regdelete +value|xp_regenumkeys|xp_regenumvalues|xp_regread|xp_regremovemultistr +ing|xp_regwrite|xp_regread|xp_regenumvalues|xp_servicecontrol|xp_avai +lablemedia|xp_enumdsn|xp_loginconfig|xp_makecab|xp_ntsec_enumdomains| +xp_terminate_process|sp_addextendedproc|xp_webserver|sp_makewebtask|\ +@\@|/)/i ) { # For Details of the kind of injection attacks this li +ne is designed to stop: +tion-cheatsheet/#SyntaxBasicAttacks print "There is a possible injection attack attempt here"; ## Secu +rity function here I would like an email to be sent with details die; }
I think there is room for a Perl module that can screen against all attacks through stored procedures of any database app.

Replies are listed 'Best First'.
Re: Preventing injection attacks
by Joost (Canon) on Apr 02, 2007 at 14:03 UTC
    That's just completely useless. I would suggest you use placeholders and/or the $dbh->quote method - or a nice abstraction layer like DBIx::Class - that way you don't have to scan your input for anything.

    Attempting to catch malicious input is misguided in most cases. You should either only allow known good - verifiable - input or make sure the content of the input doesn't matter.


    I think there is room for a Perl module that can screen against all attacks through stored procedures of any database app.
    And the problem with that is that you won't know about all potential attacks. Besides that I suspect the code to detect all known attacks would soon be orders of magnitudes larger than the code it's supposed to protect - with all the potential for bugs in and/or security holes caused by the scanning code.

      Agreed. However, if for some reason your app actually requires the ability to input actual queries (like a SQL tutorial, maybe), you should probably be relying much more on the database's built-in security model. If you give an untrusted user real access to a database that you don't want them altering/destroying, a fragile regex is not going to save you.

      As an aside for similar efforts, no regex of that length should be a one-liner. At the very least, you should be using the /x switch and commenting what you want to do. Even better would be building the regex in several chunks, so that a syntax error might have a prayer of being found.

      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Preventing injection attacks
by andye (Curate) on Apr 02, 2007 at 15:44 UTC
    Hi Win,

    Many people think that, rather than checking for particular things that you don't want, it's better to check that the input is what you do want, and only accept it if it is.

    For example, instead of saying 'don't accept input with dollar symbols in it', you could say 'only accept input consisting solely of alphanumeric characters and whitespace'.

    The logic behind this is that, if you try to check for all the possible things that could cause trouble, you're bound to miss some out, perhaps because a particular security problem is only discovered after you write your code - in that situation, there's no way you could have known about it.

    There are a couple of tools in Perl that can help with this:

    • For data coming in from web forms, there is something called Taint mode. What this does, is it forces you to 'clean' data which could have potential security problems, before you can use it.

      You do this 'cleaning' by using a regular expression to say what characters you're willing to accept, like this:

      if ($data =~ /^([-\@\w.]+)$/) { $data = $1; # $data now untainted } else { die "Bad data in '$data'"; # log this somewhere }

      (This example is from the docs linked above)

    • For sending statements out to databases, you can use something called Placeholders. What these do, is they let you separate out the data in a SQL statement, from the parts of the SQL statement that actually do things. So, if someone replaces your data with something unexpected, they can't send instructions to the database itself.

      Placeholders work like this:

      SELECT description FROM products WHERE product_code = ?

      (Example taken from the docs linked above)

    Win, I hope that's some help to you. But could I ask you to do one thing though, please? I'm asking because I can see that you've asked a very similar question recently, at this node: Preventing malicious T-SQL injection attacks. So, my request is: please could you print out, and read a couple of times, the pages that I've linked to, before coming back to the monastery with questions on the same topics?

    I can see you've just asked in the Chatterbox, "Why didn't people like my last post?", and the answer, as far as I can tell, is that some Monks are getting impatient with you because, when people answer your questions by telling you about online documentation, you're not going away and reading that documentation for yourself.

    (Personally I'm a 'no such thing as a stupid question' person, but not everyone is).

    You could also take a look at the tips in this article, The Help Vampire, a Spotter's Guide, and if you think that you might be doing some of the things they talk about (such as asking the same question multiple times, and not using your own initiative to understand the documentation), then there are some very useful tips for you to follow, on that page.

    This is all meant in the very friendliest spirit, and I hope that it reads in that way. After all, Perlmonks is here to answer questions, so everyone is absolutely entitled to ask them! Which is lucky for me, otherwise I'd have been stuck many times. :)

    Do get back to me with any queries about the 'taint mode' and 'placeholders' stuff above.

    Hope that helps, and best wishes,

    (Other relevant nodes: Database access problem, Perl DBI issue)

    The tips from the 'help vampire' page are:

    If You're a Help Vampire...

    Now you know. Stop. Of course, it's not just that easy, or nobody would ever be a Help Vampire at all.

    Before you ask a question in a community, try to find the answer elsewhere. This way you help yourself by stretching your mind and research abilities, and you learn things more thoroughly too. Plus it's good karma.

    Always try these avenues first:

    1. Keep troubleshooting. Often we learn that it's easier to give up and ask for help rather than persisting—when we'd get our breakthrough if we'd only delay giving up for another 10 minutes. Respect yourself, go a little further before giving up.
    2. Google, of course. Google partial error messages, add software names to your queries, and generally try at least 3 or 4 searches before you give it up as hopeless.
    3. Mailing lists, forums, and newsgroups. Chances are, you're not the first person on the Earth to have this problem. Luckily we live in an age where we can search the past. Check out these resources next.
    4. Docs. Sometimes they seem impenetrable, but give it a whack. The more you learn, the easier the documentation will be to understand and decipher.
    5. Ask your question—but phrase it differently. Instead of asking your question directly, ask "Has anyone has seen this problem?" or "Can anyone point me in the right direction?" Likely as not, someone will have been there before, and they might know a blog posting or other resource which can help you out. This way, you show you are respectful of their time, and understand your problem is (probably) not unique.
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Preventing injection attacks
by Bro. Doug (Monk) on Apr 02, 2007 at 16:04 UTC

    SQL Injection can definately be a thorn in your side. However, most of these problems are eliminated when you use DBI's bind method.
    #assuming you're connected, with a $dbh #my $sql = "select ? from ?"; #incorrect, thanks wfsp my $sql = "select ? from myTable"; my $sth=$dbh->prepare( $sql ) ; $sth->bind_param(1, $col_to_select ); #$sth->bind_param(2, $table ) ; #also incorrect $sth->execute ;
    DBI does a good job of escaping and db-quoting the things you bind this way. Then you can relax. If you use andye's method for filtering the input and paring away only things you -do- want via your favorite untaint method, you can relax even harder.

    Peace, monks.

    Update: wfsp has pointed out that table names shouldn't be bound with bind_params. Turns out he's absolutely correct. It's all documented in perldoc DBI. I've also fixed the code and commented out the garbage. Thanks wfsp.
    Bro. Doug :wq
      "relax even harder"++)
Re: Preventing injection attacks
by ambrus (Abbot) on Apr 02, 2007 at 17:43 UTC

    That regexp won't even compile. You have an unescaped slash and an unescaped opening parenthesis in it. But when it does compile, I think it will match too much valid data. Like, what is the branch \s+\s supposed to catch?

Re: Preventing injection attacks
by robot_tourist (Hermit) on Apr 03, 2007 at 07:51 UTC

    One good thing that has come out of this discussion is that I understand web security better now. I've developed an internal web app for my department and now that I've got it up and running with just dbh->quote()ing everything possible I think I'll start to bind up my db queries. I have to let my users input backslashes and other potentially dangerous stuff because of the nature of the data.

    How can you feel when you're made of steel? I am made of steel. I am the Robot Tourist.
    Robot Tourist, by Ten Benson

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://607824]
Approved by Joost
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (2)
As of 2020-08-13 02:21 GMT
Find Nodes?
    Voting Booth?
    Which rocket would you take to Mars?

    Results (69 votes). Check out past polls.