Secure PHP Programming for PHP beginners.
Page 1 of 2 12 LastLast
Results 1 to 10 of 19

Thread: Secure PHP Programming for PHP beginners.

  1. #1
    Senior Member
    Join Date
    Nov 2001
    Posts
    1,255

    Post Secure PHP Programming for PHP beginners.

    A common mistake I have seen in PHP code (which I made myself when I began writing PHP) is to not do various things to secure user input.

    When accepting input from a user, there are three simple things you can and should do to make your project more secure.
    1. Use GET and POST accordingly.
    2. Take a list of known-good characters, and filter the rest out.
    3. Check your lengths!

    Step 1: Use GET and POST accordingly.

    We'll start with a very simple form that contains a person's email address, and will be used to subscribe to a mailing list by way of entering the email address into a database.

    Code:
    <form name="MailingListForm" action="./Signup.php" method="POST">
      <input type="text" name="Email" maxlength="45">
    
      <input type="submit">
    </form>
    Now, this form has a single user-modifiable element: Email.

    On the PHP script side of things, the first thing you need to do is get the data from the form.

    This is where I find programmers are either lazy, or simply haven't learned any better, and they don't use the PHP4+ arrays $HTTP_POST_VARS or $HTTP_GET_VARS. As you might guess, these two arrays contain both POST and GET variables respectively. If you do not access and set your variables manually this way, you cannot guarantee that your variables are being set in the proper fashion, and it introduces a level of insecurity.

    Unfortunately, PHP does not require the use of these two arrays, as if you simply access a url via script.php?var=value then $var gets created on the target script (whether you need it or not) and is set to "value".

    The difference between POST and GET.
    The simplest way to observe the differences between POST and get is to look at how they are read in by the PHP interpreter.
    A GET variable is passed onto the script via the URL in the form of: script.php?var=val&var2=val2.
    A POST variable is passed onto the script via a form with the script as its action, and the method set to POST.

    How to use them effectively.
    First, you need to establish which method you will need. In our example, we would only want the data from the Email variable to be POSTed, so therefore, we will set $email to the value of $HTTP_POST_VARS["email"].

    example:
    Code:
    $email = $HTTP_POST_VARS["email"];
    if (!$email) {
       echo "Error! No email address entered!";
       exit;
    }
    In this manner, someone accessing Signup.php?email=signmeupnow@hotmail.com would get an error that reads: Error! No email address entered!.

    It is always a good idea to set your variables yourself, so that you have more control over what data is able to get to your script, and what you do with it once it is there.

    Note that this will only prevent someone from simply typing in said url from setting the $email variable. If they create their own form, they can still bypass this, which leads us into the next section.

    Step 2: Take a list of known-good characters, and filter the rest out.

    The next step is to filter out characters you don't want. Email addresses must conform to a certain standard, therefore, you have an exact idea of what you will need to appear in the variable.

    Everything is great, unless you encounter a malicious user who is attempting to inject SQL into your database server, or perhaps even alter some PHP. Keep in mind that PHP can run shell commands using the backticks (`), so it's a good idea to filter out any unnecessary characters.

    To do that, we will pass our variable through a list of known-good characters using the preg_replace function. We'll integrate this right away into our script.
    Code:
    $email = preg_replace("/[^A-Za-z0-9.\-_@]/","",$HTTP_POST_VARS["email"]);
    if (!$email) {
       echo "Error! No email address entered!";
       exit;
    }
    Now, if someone tried to enter in something like "bill@microsoft.com ' ; delete from users ;", which is an attempted SQL injection, it would end up looking like: "bill@microsoft.com delete from users ". this way you can at least filter out any dangerous characters. You would obviously want to add some specifics for email checking, but that is beyond the scope of this document.

    To simplify this process, I often use a centralized set of functions to do all the above for me.
    Code:
    $KG_CHARS="A-Za-z0-9.\-_@";
    function getPOST( $postvarname ) {
       return preg_replace("/[^$KG_CHARS/","",$HTTP_POST_VARS[$postvarname]);
    }
    function getGET( $getvarname ) {
       return preg_replace("/[^$KG_CHARS/","",%HTTP_GET_VARS[$getvarname]);
    }
    Using these functions gives you a tremendous advantage in that the process is both centralised (meaning its simpler to add characters) and it also reduces your code to:
    Code:
    $email = getPOST("email");
    3. Check your lengths!

    One of the more often overlooked things when it comes to database connectivity is length checking on user input. As some of you may know, when you create a database table in any SQL server, you decide upon and set the field length in characters (with certain exceptions). Many lazy programmers simply set the maxlength parameter on the form and ignore any such checking on their variables before attempting to insert them into the database.

    As you've no doubt noted, the maxlength parameter is used in the form above. This is a good thing, because it will let the user know if they're using an email address that's too long for your site to accept. However, it should not be your only method for checking the data's length.

    The danger here is that most SQL errors will spit out the full path to the database server's installation, which can help an attacker in determining how and where the database has access to, if there should be any SQL-injectable code. It is also not very good to have bug-riddled sites.

    To prevent this, simply perform an strlen() operation on it to determine the length. I often create functions for this purpose as well, which return true or false if there length exceeds the requirements of the database.

    Code:
    function lenCheck( $var, $maxlen ) {
       if (strlen($var) > $maxlen) {
          return false;
       } else {
          return true;
       }
    }
    And in your code, you would do something along the lines of:
    Code:
    if (!lenCheck($email, 45)) {
       $email = NULL;
    }
    so that your error checking code would grab the email address and say it is of an invalid length.

    A complete, functional example would be:
    Code:
    <?PHP
    $KG_CHARS="A-Za-z0-9.\-_@";
    function getPOST( $postvarname ) {
       return preg_replace("/[^$KG_CHARS/","",$HTTP_POST_VARS[$postvarname]);
    }
    function getGET( $getvarname ) {
       return preg_replace("/[^$KG_CHARS/","",%HTTP_GET_VARS[$getvarname]);
    }
    function lenCheck( $var, $maxlen ) {
       if (strlen($var) > $maxlen) {
          return false;
       } else {
          return true;
       }
    }
    
    $email = getPOST("email");
    if (!lenCheck($email, 45)) {
       $email = NULL;
    }
    if (!$email) {
       echo "There was an error while attempting to enter your email address into our
    mailing list database.
    
    This may be caused by one of the following reasons:
    
    -Your email address is not entered in the correct format.
    
    -Your email address is longer than our 45 character limit.
    
    -You accessed this page in an incorrect fashion.
    ";
       exit;
    }
    
    // Place code here to handle inserting the email address into the database.
    
    ?>
    It's also a good idea to try to be verbose and direct the user to to things that will possibly correct the error.

    I hope this helps, and I look forward to any/all feedback.

    PS: Edited for formatting. No code was changed, it was merely spaced differently to prevent horizontal scroll.
    Chris Shepherd
    The Nelson-Shepherd cutoff: The point at which you realise someone is an idiot while trying to help them.
    \"Well as far as the spelling, I speak fluently both your native languages. Do you even can try spell mine ?\" -- Failed Insult
    Is your whole family retarded, or did they just catch it from you?

  2. #2
    Senior Member
    Join Date
    Nov 2001
    Location
    Ireland
    Posts
    735
    Good tutorial, well done.
    Once I wrote a message board system in PHP and allowed HTML to be posted. I knew that this could mess up the page's formatting if someone entered a rude <BODY> tag or something, but soon enough I realised that it was also a huge security risk, like if someone was to write a <?PHP> script, which could easily delete or overwrite files. So I had 2 options:
    1) Rename the results page from results.php to results.html
    or
    2) Use the htmlentities() function which translate < to &lt; and > to &gt;
    I just decided to rename the page and filter out the message for certain tags, such as BODY.

  3. #3
    Senior Member
    Join Date
    Mar 2002
    Posts
    137
    Sorry I bumped up this is very useful.

  4. #4
    Junior Member
    Join Date
    Sep 2004
    Posts
    26

    PHP, is interesting.

    Do i have to be a pro at things like html, and java script to actually get a hold on this beast?
    is this a dream

  5. #5
    Senior Member
    Join Date
    Nov 2001
    Posts
    1,255
    You really should have created a new thread for this, but the answer is, it helps, and I would generally encourage it. However, PHP is a separate language, and you don't necessarily need to output (X\D)HTML.
    Chris Shepherd
    The Nelson-Shepherd cutoff: The point at which you realise someone is an idiot while trying to help them.
    \"Well as far as the spelling, I speak fluently both your native languages. Do you even can try spell mine ?\" -- Failed Insult
    Is your whole family retarded, or did they just catch it from you?

  6. #6
    Senior Member
    Join Date
    Jan 2002
    Posts
    1,207
    Some good important stuff, but it seems a shame a PHP security tutorial didn't mention register_globals.

    The single most important security measure a PHP app should take, is to disable register_globals. Ideally, place a check to ensure that if register_globals is accidentally re-enabled, the application ceases to function until it is disabled.

    Slarty

    PS: I missed this tut 1st time around

  7. #7
    Senior Member
    Join Date
    Nov 2001
    Posts
    1,255
    Originally posted here by slarty
    Some good important stuff, but it seems a shame a PHP security tutorial didn't mention register_globals.

    The single most important security measure a PHP app should take, is to disable register_globals. Ideally, place a check to ensure that if register_globals is accidentally re-enabled, the application ceases to function until it is disabled.
    Slarty, this tutorial is over two years old, and was written to promote writing secure code, *NOT* securing PHP installations themselves. If your PHP is written properly, register_globals doesn't even enter the equation. The register_globals crutch is a configuration-time option that only promotes poor programming practices. The tutorial is intended to promote good programming practices, not encourage the use of crutches, or discuss administration practices.
    Chris Shepherd
    The Nelson-Shepherd cutoff: The point at which you realise someone is an idiot while trying to help them.
    \"Well as far as the spelling, I speak fluently both your native languages. Do you even can try spell mine ?\" -- Failed Insult
    Is your whole family retarded, or did they just catch it from you?

  8. #8
    register_globals isnt an issue if you code decently anyway however most people dont, hence the major concern around it, but meh not my issue

  9. #9
    Senior Member
    Join Date
    Jan 2002
    Posts
    1,207
    A secure well-written PHP app can easily contain a vulnerability when register_globals is enabled, but be secure otherwise.

    This is why my apps always check for register_globals and produce an error message if it's on.

    Slarty

  10. #10
    Junior Member
    Join Date
    Mar 2006
    Posts
    9
    Hi

    Just thought i would make a quick mention of the php function

    mysql_real_escape_string()

    If you are interested in user input and forms with MYSQL this is a must.

    I am not very great at php so ill just say that.

    But the manual shows a good example of its use

    Manual Link Here

    Cheers

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

 Security News

     Patches

       Security Trends

         How-To

           Buying Guides