PHP 5 Advanced: Visual QuickPro Guide
[Excerpted from PHP 5 Advanced: Visual QuickPro Guide by Larry Ullman. Copyright © 2007. Used with permission of Pearson Education, Inc. and Peachpit Press.]
With more and more personal information being stored on the Web—credit card data, social security numbers, maiden names, favorite pets—today's PHP developer cannot afford to be ignorant when it comes to security. Sadly, most beginning programmers fail to understand the truth about security: there is no such thing as "secure" or "insecure." The wise programmer knows that the real question is how secure a site is. Once any piece of data is stored in a database, in a text file, or on a Post-it note in your office, its security is compromised. The focus in this chapter is therefore how to make your applications more secure.
This chapter will begin by rehashing the fundamentals of secure PHP programming. These are the basic things that I hope/assume you're already doing. After that a quick example shows ways to validate different kinds of data that might come from an HTML form. The third topic is the new-to-PHP 5 PECL library called Filter. Its usage isn't very programmer-friendly, but the way it wraps all of the customary data filtering and sanitizing methods into one interface makes it worth knowing. After that, two different uses of the PEAR Auth package show an alternative way to implement authorization in your Web applications. The chapter will conclude with coverage of the MCrypt library, demonstrating how to encrypt and decrypt data.
Remembering the Basics
Before getting into demonstrations of more particular security techniques, I want to take a moment to go over the basics: those fundamental rules that every PHP programmer should abide by all of the time.
To ensure a basic level of security
Do not rely upon register_globals.
The advent of register_globals once made PHP so easy to use, while also making it less secure (convenience often weakens security). The recommendation is to program as if register_globals is off. This is particularly important because register_globals will likely disappear in future versions of PHP.
Initialize variables prior to using them.
If register_globals is still enabled—even if you aren't using them—a malicious user could use holes created by noninitialized variables to hack your system. For example:
$authis not preset to
FALSEprior to this code, then a user could easily make themselves authorized by passing
$_COOKIE['auth']to this script.
Verify and purify all incoming data.
How you verify and purify the data depends greatly upon the type of data. You'll see many different techniques in this chapter and the book.
Avoiding Mail Abuses
A security concern exists in any Web application that uses the
mail()function with form data. For starters, if someone enters their "to" email address as email@example.com,firstname.lastname@example.org, you'll now be sending two emails. If a malicious user enters 500 addresses (perhaps by creating their own form that submits to your same page), you're now sending out spam! You can avoid this by using regular expressions to guarantee that the submitted value contains just one address. Or you could search for a comma in the submitted email address, which wouldn't be allowed. But that won't solve the problem entirely.
mail()function takes separate arguments for the "to" address, "from" address (or other additional headers), subject, and body, all four values are put together to create the actual message. By submitting specifically formatted text through any of these inputs, bad people can still use your form to send their spam. To guard against this, you should watch for newline (
\n) and carriage returns (
\r) within the submitted data. Either don't send emails with these values or replace them with spaces to invalidate the intended message format. You should probably also make sure that you (or someone involved with the site) receives a copy of every email sent so that close tabs can be kept on this area of the server.
Be careful if you use variables for included files.
If your code does something like
then you should either make sure that
$pagedoes not come from an outside source (like
$_GET) or, if it does, that you've made certain that it has an appropriate value. See the technique in Chapter 2, "Developing Web Applications."
Be extra, extra careful when using any function that runs commands on the server.
popen(), and the backticks (
``). Because each of these runs commands on the server itself, they should never be used casually. And if you must use a variable as part of the command to execute, perform any and all security checks on that variable first. Also use the
escapeshellcmd()functions as an extra precaution.
Consider changing the default session directory or using a database to store session data.
An example as to how you would do this is discussed in Chapter 3, "Advanced Database Concepts."
Do not use browser-supplied filenames for storing uploaded files on the server.
When you move a file onto your server, rename it to something safe, preferably something not guessable.
Do not reveal PHP errors on live sites.
One of the most common ways to hack a site is to try to "break" it—do something unexpected to cause errors—in the hopes that the errors reveal important behind-the-scenes information.
Nullify the possibility of SQL injection attacks.
Use a language-specific database escaping function, like
mysqli_real_escape_data(), to ensure that submitted values will not break your queries.
Program with error reporting on its highest level.
While not strictly a security issue, programming with error reporting on its highest level can often show potential holes in your code.
phpinfo()scripts on the server.
Although vital for developing and debugging PHP applications,
phpinfo()scripts reveal too much information and are too easily found if left on a live site.