PHP DevCenter

oreilly.comSafari Books Online.Conferences.

We've expanded our LAMP news coverage and improved our search! Search for all things LAMP across O'Reilly!

Search
Search Tips

advertisement

Print Subscribe to PHP Subscribe to Newsletters

Ten Security Checks for PHP, Part 2

by Clancy Malcolm
04/03/2003

In the previous article, we explored five security checks for PHP code; in this article we explore five more.

Use the .php extension for all script files

Many PHP programmers use .inc or .class extensions for library and configuration files that are accessed by the include function. If a malicious user fetches the URL for the .inc or .class file in their browser they will be able to see the contents of these files, including any PHP code. This may reveal intellectual property, passwords or weaknesses in your code.

What to Look For

Examine the file names of all script files.

Possible Fixes or Improvements

  • Use the .php extension for all script files
  • Place library and configuration files outside the web server's document root directory

Place sensitive content outside the document root directory

Many PHP systems are designed to restrict access to documents or images through user authentication and access control lists. However, these documents are frequently stored as files in a subdirectory of the directory containing the PHP scripts. This makes these files available directly by using the appropriate URL in your browser.

Don't put secured content under the application root; for example, don't put an image which is meant to be password protected under the application root.

What to Look For

Examine the placement of directories used to store files containing privileged content.

Possible Fixes or Improvements

  • Store content as files in a directory outside the web server's document root directory.
  • Store content in a database.
  • Use web server features such as Apache's .htaccess files to prevent direct access to content directories.

Related Reading

Web Programming CD Bookshelf
Six Bestselling Books on CD-ROM
By A publication of O'Reilly Media

Beware of Shared Servers

Many PHP sites take advantage of cheap third-party hosting. Such hosting usually involves sharing a server with other users. Another user may be able to use a PHP script or shell access to modify, access, or delete your files or to determine database passwords. Another potential attack is the ability to create a session file (by default stored in /tmp) that would allow the malicious user to bypass your authentication.

What to Look For

If you are using a shared server look at the configuration of the server using the phpinfo function. Also examine the permissions on sensitive files.

Possible Fixes or Improvements

  • Use a dedicated server instead. Hosting companies usually have dedicated servers available at higher prices, but the security and performance gains may justify the expense.
  • Ensure the hosting company turns on the safe_mode configuration setting. (You can check by writing a script that runs the phpinfo function.) However, the safe_mode function can also prevent the execution of other programs, limiting the functionality of your site.
  • Set file permissions such that the web server can only read files if it knows their name. (On Unix systems, give directories modes like 711.)

Avoid Loose Typing Intricacies

PHP will often convert the type of a variable from one type to another type to suit the current context in which it is being used. These problems are hard to identify, but have lead to holes in popular PHP software such as phpMyAdmin. Consider the following code:

<?php
    // A simple user list - the key of each array is the user number and
    // the value is the password
    $users[0] = ""; // Guest user
    $users[1] = "password1";
    $users[2] = "password2";
 
    // Check that the user has entered a user ID of 0, 1 or 2
    if ($user_id < 0 || $user_id > 2 || !isset($user_id)) {
        die("Invalid user ID");
    }
 
    // Check that users apart from guest have entered the correct password
    if ($user_id != 0 && $password != $users[$user_id]) {
        die("Password invalid");
    }
 
    // Print a message telling the user what type they are
    if ($user_id) {
        echo "You are an authenticated user";
    } else {
        echo "You are a guest user";
    }
?>

The code appears to have done the necessary checking to ensure that a valid user ID is provided. A list of parameters and outputs is shown below:

user_id value password value Output Output Correct?
4 x Invalid User ID Yes
1 y Password invalid Yes
1 password1 You are an authenticated user Yes
0 - You are a guest user Yes
a z You are an authenticated user No
00 z You are an authenticated user No

What to Look For

This problem can be hard to identify, but the following areas of code may be vulnerable:

  • Comparisons of user entered values with numeric values.
  • Inconsistent expressions. For example, using a combination of if ($x != 0) and if ($x).

Possible Fixes or Improvements

  • Validate user input with type-casting operations in mind.
  • Use type checking functions like is_long.

Escape or Avoid User Input When Constructing Command Strings

Using functions like exec and eval can add a lot of flexibility to your program. However, caution is necessary to avoid the possibility for users to execute arbitrary commands.

What to Look For

Examine all functions which can execute system commands or PHP code including:

  • eval
  • preg_replace (when used with the /e modifier this will treat the replacement parameter as PHP code).
  • exec
  • passthru
  • system
  • popen
  • `` (backticks - can be used to execute commands)

Beyond the Code - A strong security design

The previous steps have all been programming related, but much of an applications security should be determined by a thoughtful design before the programming commences.

Secure application design is a topic in its own right, but some basic tips are listed briefly below.

  • Consider using HTTPS for transmission encryption. This can be important even if the privacy of your data is not a priority; eavesdroppers could obtain password or session identifiers and then use these to bypass your application's security.
  • Consider restricting access to sensitive pages based on host/domain name or IP address. This can be done using the web server features such as Apache's .htaccess files or by checking variables in your PHP script such as $REMOTE_ADDR.
  • Use existing security packages for authentication such as PHPLib.

Conclusion

All languages have security weak points, but with close scrutiny focusing on those weak points many security holes can be avoided. Following the steps in this article as part of everyday coding and formal code reviews should help provide more secure applications.

References

  • A Study In Scarlet - Exploiting Common Vulnerabilities in PHP Applications - Shaun Clowes, SecureReality
  • Security flaws in PHP - Jo Henrik Endrerud, zez.org
  • PHP Manual - Stig Sæther Bakken, et al, PHP.

Clancy Malcolm is a private web application consultant and contributes to numerous open source projects.


Return to the PHP DevCenter.


Comments on this article
Full Threads Oldest First

Showing messages 1 through 8 of 8.

  • Avoid Loose Typing Intricacies - fix
    2003-04-07 23:32:18  ljweb [View]

    Rather than the
    if ($user_id < 0 || $user_id > 2 || !isset($user_id)) {
    line, I would advice the use of
    if (is_int($user_id) && isset($users[$user_id])) {

    The reason is, that even how small or large a usertable must be, there will always be someone skipping out from time to time, leaving empty slots in the list. Checking for larger/less-than is then not optimal and will produce yet another security flaw, as the subject of this very article states. Using "loginnames" rather than a number, would remove this problem same time.

    I know, the code produces is not intended for production site (or I hope so), but the examples provided should rate as code worth copying and following.

    / Lars
    www.ljweb.com
    • Avoid Loose Typing Intricacies - fix
      2003-04-08 00:58:01  clancymalcolm [View]

      The code is certainly not intended for a production site - the code was given as an example of what _NOT_ to do. The text discussing the code illustrates these flaws. It is based on the security hole found in PHPMyAdmin some time ago, but simplified for clarity and the ability to run as a stand-alone script. Your suggestion is certainly valid and follows the advice in the "Possible Fixes" section for this hole.

      If you are designing an application from scratch I would advise using a standard library such as the PEAR authentication library or the older PHPLib library - this way you get the benefit of code that is (hopefully) reviewed by lots of other developers and well tested. However, there are still many applications that use their own authentication mechanisms and these are frequently flawed. The example aims to illustrate a flawed implementation so that you are able to identify and fix such holes.

      Cheers,
      Clancy
  • Part 1/Part 2 Fixed
    2003-04-04 13:51:40  chromatic | O'Reilly AuthorO'Reilly Blogger [View]

    Sure enough, somehow part one ended up as the final version of this article. We backed up one revision and part two was there, waiting for us. It should be here in the next couple of minutes.

    Please accept my apologies for the confusion. Thanks for spotting this so quickly, too!
  • PART 2 APPEARS TO BE SAME AS PART 1
    2003-04-04 09:24:46  anonymous2 [View]


    Parts 1 and 2 of this article are identical
  • Part 2?
    2003-04-04 04:07:09  anonymous2 [View]

    This article seems to be exactly the same as part 1!
    • Part 2 is diiferent today
      2003-07-24 07:01:21  anonymous2 [View]

      To take part to this!

      The first article deals with global variables, access and quotes, and include, dansgerous function... on the 2003-7-24.

      Theese are very very good tips.

      Thomas.
    • Part 2 missing?
      2003-04-04 05:59:19  anonymous2 [View]

      look, folks: 1!=2
      • Part 2 missing?
        2003-04-04 09:02:41  anonymous2 [View]

        *cough* yeah, it does - the content of this article is the same as the part 1

        http://www.onlamp.com/pub/a/php/2003/03/20/php_security.html


Recommended for You

Tagged Articles

Post to del.icio.us

This article has been tagged:

php

Articles that share the tag php:

Understanding MVC in PHP (477 tags)

The PHP Scalability Myth (123 tags)

The Dynamic Duo of PEAR::DB and Smarty (53 tags)

PHP Form Handling (43 tags)

Very Dynamic Web Interfaces (39 tags)

View All

security

Articles that share the tag security:

Secure RSS Syndication (169 tags)

Google Your Site For Security Vulnerabilities (74 tags)

Building a Desktop Firewall (64 tags)

The Next 50 Years of Computer Security: An Interview with Alan Cox (42 tags)

Protect Yourself from WiFi Snoops (40 tags)

View All

development

Articles that share the tag development:

Rolling with Ruby on Rails (579 tags)

What Is Web 2.0 (129 tags)

Ajax on Rails (119 tags)

Very Dynamic Web Interfaces (97 tags)

Understanding MVC in PHP (64 tags)

View All

Sponsored Resources

  • Inside Lightroom
Advertisement

Sponsored by:

Sign up today to receive special discounts,
product alerts, and news from O'Reilly.
Privacy Policy >
View Sample Newsletter >
  • Youtube
  • http://www.youtube.com/OreillyMedia
  • Twitter
  • Subscribe
  • View All RSS Feeds >
O'Reilly Media

800-889-8969 or 707-827-7019
Monday-Friday 7:30am-5pm PT
©2011, O'Reilly Media, Inc.
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
  • About O'Reilly
  • Academic Solutions
  • Contacts
  • Customer Service
  • Careers
  • Press Room
  • Privacy Policy
  • Terms of Service
  • Writing for O'Reilly
  • Community
  • Authors
  • Forums
  • Membership
  • Newsletters
  • RSS Feeds
  • User Groups
  • More O'Reilly Sites
  • igniteshow.com
  • makerfaire.com
  • makezine.com
  • craftzine.com
  • labs.oreilly.com
  • Partner Sites
  • PayPal Developer Zone
  • O'Reilly Insights on Forbes.com