Important security tips in php

Post Reply
User avatar
Neo
Site Admin
Site Admin
Posts: 2642
Joined: Wed Jul 15, 2009 2:07 am
Location: Colombo

Important security tips in php

Post by Neo » Sun Feb 28, 2010 11:41 pm

Security should be a top concern throughout the development of any PHP web application. There are some very simple measures you can take to protect your application from potential abuse. This post will cover some of the basics of PHP security. For more detailed explanations of good security practices, check out the PHP Security Guide.

I do not consider myself a PHP security expert, but these are things that every developer should know. Also keep in mind that security is a process and not a result.
  1. Input Filtering
    Assume everything is dirty until proven clean. Filtering all data from external sources is probably the most important security measure you can take. This can be as easy as running some simple built-in functions on your variables.

    When it comes to accepting user input, never directly use anything in $_GET or $_POST. Check each value to make sure it is something expected and assign it to a local variable for use.

    Code: Select all

    // input filtering examples
     
    // Make sure it is an integer
    $integer = intval($_POST['variable_name']);
     
    // Make it safe to use in a URL
    $url_string = urlencode($_POST['variable_name']); 
    You can also check a value against a list of acceptable values. Here are two methods of doing this:

    Code: Select all

    $page = 'home'; // initialize the variable
     
    // Check input against a white-list of known options
    $valid_options = array();
    $valid_options[] = 'home';
    $valid_options[] = 'downloads';
    $valid_options[] = 'about';
     
    if(in_array($_GET['page'], $valid_options))
    {
       $page = $_GET['page'];
    }
     
    // OR this also works
    switch($_GET['page'])
    {
       case 'home':
       case 'downloads':
       case 'about':
          $page = $_GET['page'];
          break;
    } 
    PHP as of version 5.2 provides a set of filtering functions designed just for the purpose of filtering user data. The filter_input() function is used to access a filtered version of input variables. This way you never have to touch the raw input via the $_GET or $_POST arrays.

    Code: Select all

    // filter_input examples
     
    // Make sure it is an integer
    $integer = filter_input(INPUT_POST, 'variable_name', FILTER_SANITIZE_NUMBER_INT);
     
    // Make it safe to use in a URL
    $url_string = filter_input(INPUT_POST, 'variable_name', FILTER_SANITIZE_ENCODED);
     
    // Make sure it is a valid URL
    $url = filter_input(INPUT_POST, 'variable_name', FILTER_VALIDATE_URL); 
  2. Output Filtering
    It is also important to filter what comes out of your applications. You want to avoid outputting the wrong characters and breaking the page rendering. This is also important in order to block certain attacks involving JavaScript injected by malicious users. There are a few functions to know for cleaning up text to display to the user:
    • htmlspecialchars(): Converts special HTML characters to entities
    • htmlentities(): Converts all possible characters to HTML entities
    • strip_tags(): Remove all HTML tags from a string (you can also selectively allow tags using the second optional parameter)

    Code: Select all

    $text = '<a href="test">Test</a>';
    echo htmlspecialchars($text); // <a href="test">Test</a>
    echo strip_tags($text); // Test 
  3. Database Queries
    If your application uses a database to store data, this is another source of potential vulnerabilities. SQL Injection is a very common attack that involves maliciously crafted user input designed to change the logic of a query. This potentially allows the user to run any kind of query or bypass security measures. Stopping it is usually as easy as properly escaping data, or using prepared statements.

    Escape functions:
    • mysql_real_escape_string(): For use with the mysql_* functions
    • mysqli::escape_string(): For use with the MySQLi extension/class
    • pg_escape_string(): For use with PostgreSQL
    • addslashes(): This is a generic escape function to use only if your database engine does not have a specific function
    Here is an example using each function:

    Code: Select all

    // $db refers to database connection resource/object
    $name = "O'reilly"; // Contains a quote that will break the query
     
    // MySQL via mysql_*
    $safe = mysql_real_escape_string($name, $db);
     
    // MySQL via MySQLi
    $safe = $db->escape_string($name); // OOP Style
    $safe = mysqli_real_escape_string($db, $name); // Procedural Style
     
    // PostgreSQL
    $safe = pg_escape_string($db, $name);
     
    // Generic (last resourt)
    $safe = addslashes($name); 
  4. Hide Your Errors
    It's never a good idea to show the world your errors. Not only does it make you look bad, it also might give malicious users another clue to help them break your site. You should always have display_errors disabled in a production environment, but continue logging errors with log_errors for your own information.

    These PHP configuration directives are suitable for a production server:

    Code: Select all

    display_errors 0
    log_errors 1
  5. Use POST for Dangerous Actions
    There are two common methods used to send data to a PHP application, GET and POST. GET works by adding variables to the end of URL's (eg. http://www.example.com/process.php[b]?a ... ete&id=123[/b]). POST works by sending variables in the body of the request (normal users will not see them). It is important to carefully consider which method to use for a certain task.

    You should generally stick to POST when you are performing a potentially dangerous action (like deleting something). The reason is that is is much easier to trick a user into accessing a URL with GET parameters than it is to trick them into sending a POST request. Take this example:

    Code: Select all

    <img src="http://www.example.com/process.php?action=delete&id=123" /> 
    If a user with an active session on your site visits another web page with the above image tag, the user's browser will quietly send a request to your site telling it to delete record 123.

    Keep in mind that other precautions should also be taken to ensure requests are legitimate under a secure session. It is also easily possible to create a form that does the same as above using a POST request, so don't assume that method is "safe" either. See sections 2 and 4 of the PHP Security Guide for more information on form and session security.
Conclusion
This article is just a general overview of PHP security practices. For more detailed explanations if the topics covered here as well as some not covered, see the PHP Security Guide by the PHP Security Consortium. There are also many other articles and books on the topic that you may be interested in.

Of course there may be some that disagree with some of the details in this post. Don't hesitate to post a comment if you have any corrections, improvements, or additions!
Post Reply

Return to “PHP & MySQL”