GreyBeard Inc.

    
    
     

Writing secure PHP code

    People often ask me, "Jason, oh great PHP master, how can I write secure PHP code?". To this I respond "Climb back down the mountain and return to your home my son, the answers will find you there ... as long as you click over to my blog and wait until I get this post done. Now GO!". Seriously though, about the only thing I am a master of is run on sentences, embellishing, and the sometimes spooky but usually droll ability to raise either of my eyebrows individually. I have however written quite a bit of PHP over the years and have some suggestions to help others avoid some of the mistakes I have made in the past. So without further ado, here is my somewhat short, seemingly solid, sometimes sordidly sarcastic, synopsis of secure scripting suggestions. 

  • User input is the Antichrist. It will whisper sweetly in your ear and promise to be true, but it can't be trusted. One common misconception regarding user input is not realizing the big picture when it comes to web pages. Lets use form submission as an example. just because we previously sent a user a form with fields a, b, and c does not mean we will receive all 3 fields in the resulting POST operation. The entire web page, including any javascript form validation, is sent to the user before they submit it, therefore a crafty visitor can submit the form with no fields, extra fields, and anything they want as values. So before you start processing form fields you *think* are present, make sure with isset(). PHP is loosely typed, but when looking at user input type-casting values enhances security tremendously. If you can use a non zero integer for a form field value (such as in a select list), you can virtually erase any wrongdoing with that field like so:

    $bad_fld = 0;
    if (isset($_POST['something_that_should_be_an_integer'])) {
        $bad_fld = (int) $_POST['something_that_should_be_an_integer'];
    }
    if ($bad_fld) {
          echo 'The field had a valid non-zero integer';
    }
    else {
        echo 'The field was either gone, set to zero, or not an integer';
    }


    You may want to differentiate between a zero value and one that is not set, the latter being a case in which the users has altered the form submission in a possibly malicious way. Remember that any external data, be it from a user, a database that your software did not populate, or even rss feeds, cannot and should not be trusted.
  • If you carelessly redisplay, you pay. Cross site scripting attacks hinge on the ability to alter a web page's content to include unauthorized code. The primary source of this is to redisplay data that was submitted by a user or that came from an external source. Always clean out this data before putting it in a web page. htmlentities(), htmlspecialchars(), striptags(), str_replace() are all your friends in this department. If you have the unenviable task of having to display possibly insecure content with the requirement that it maintains it's HTML formatting, you will need a more heavy duty solution. I like htmlfilter, written by an old friend from the days I worked on the Squirrelmail project. It supports whitelisting or blacklisting, and has several extra XSS checks that will slip right past many other cleaning techniques. I personally recommend whitelisting whenever possible over blacklisting. From a security standpoint it just makes more sense.
  • Computer morons make the best testers. I have had the pleasure of working with a few very bright individuals with a knack for thorough testing methods. But far and away the best way to test out a pages functionality is to let a nearly computer illiterate user have a go at it. You will be amazed at how quickly your for-sure-secure setup falls to it's knees under the strain of unintended and misguided use.
  • Brain good. Use brain. The best way to secure your PHP code is to think about it. Study the ways your logic can be avoided or misused and eliminate those possiblities. Read up on the ways crackers abuse other PHP applications. Use the excellent documentation at php.net to learn about potentially dangerous functions that are best avoided if at all possible (like system calls or regular expression callbacks). If you are doing database work be prepared to do some homework on SQL injection avoidance and proper database access techniques.

       Hopefully these ideas are some food for thought on how you can improve the security of your PHP scripts. By no means is this intended to be exhaustive or thorough, but instead I hope it nudges readers in the right direction when considering security and PHP. If you start a project with security in mind then the chances of the final product being more secure are greatly increased. PHP is powerful, and can make a small task easy to accomplish with minimal work, but remember, with great power comes great responsibility. PHP scripts can be secure, but it takes hard work and a lot of thought to cover all the bases.


Images
No Images with this post
Comments
tainted
Posted by slushpupie 268 days, 15 hours ago
Perl has a wonderful feature 'taint' which marks variables that came in contact with the outside world (ie- users) until you have done something to cleanse them. If only all languages had that feature. There are some patches to support taint in PHP, but as far as I know it isnt really mainstream yet. But you can use your brain- before you use a variable, trace it backwards and make sure you know exactly where it came from, and what happened to it along the way. Most of the time its easy, but sometimes it gets more complex. In the worst case if you cant tell, sanitize it yourself.

Add a comment


Name:
Email:
Subject:
Comment:
Security Image:
security image
Enter the letters you see above.