PHP Security Primer and Cheat Sheet
Most budding web programmers are primarily concerned with building things that work and don't spend as much time as they probably should thinking and learning about application security. This is normal and not particularly troublesome as long as your projects remain private or personal. However, concerns about application security take center stage once you start working on collaborative, public projects.
Unfortunately, PHP is a language with a number of noteworthy security concerns. In this primer on PHP security, we'll take a look four critical aspects of PHP web application security: language features, language configuration, user data and authentication, and malicious attacks. We'll introduce each aspect, touch on the key factors you need to be aware of as a budding PHP programmer, and link to in-depth technical resources you can use to make sure your applications are properly secured.
PHP Language Features with Security Implications
Programmers need to be aware of certain PHP language features that can introduce bugs and vulnerabilities into programs. Let's look at three such features briefly: weak typing, error handling, and URL routing.
When we say that PHP is weakly or loosely typed, this means that in some cases PHP will compare two values without paying much attention to the type of the value — whether the value is a boolean, number, string, array, object, or something else. When comparing the equality of values in PHP, either
== (equal) or
=== (identical) may be used. Use the first, and PHP will compare the values and return judgment without paying much attention to value types. Use the second, and PHP will take value type into consideration.
The use of
== in particular can create problems. For example:
// Ask PHP the following, and the answer will be 'true' if ( 0 == '0' ) echo 'true'; // Yet, ask PHP this, and the answer will be 'false' if ( 0 === '0' ) echo 'true'; else echo 'false';
This behavior may seem convenient since you won't have to convert the string
'0' into a number to compare it to
0. However, this can create confusion and once you include values like
false in the mix, things get complicated.
// Compare these two values, and the answer will be 'true' if ( null == false ) echo 'true'; else echo 'false'; // Yet, null and false are not both equal to '0' if ( false == '0' ) echo 'true'; // will return true else echo 'false'; if ( null == '0' ) echo 'true'; else echo 'false'; // will return false
Because of the confusion that can be caused by loose type comparisons (
==), most programmers recommend avoiding loose type comparisons entirely and sticking to strict comparisons (
Learn more about PHP comparison operators: PHP Manual, Comparison Operators.
The underlying philosophy behind error handling in PHP is that the program should be allowed to continue to run unless the error is exceptionally problematic — basically, "it's better to do something than nothing."
PHP errors are broken into three groups: errors, notices, and warnings. Only errors will keep a program from executing. Notices and warnings will be logged, but the program will keep humming along despite encountering them. This is in contrast with many other programming languages where any small error will grind program execution to a halt.
Flexible and rather permissive error handling is a dual-edged sword. On the one hand, it means that a PHP application will keep running despite the existence of many minor errors. On the other hand, this means that most PHP applications do generate a fair share of error messages and may behave in unexpected ways.
What tends to happen is that PHP programmers learn to tune out warnings and notices, and instead just worry about whether or not an application works. Error displaying can be easily turned off leading many developers to turn off error reporting and only pay much attention to errors that stop the program dead in its tracks.
However, notices and warnings are produced when parts of a program aren't functioning properly, or at all. As a result, it's entirely possible to introduce avoidable security bugs and unexpected behavior into an application, and end up shipping code with avoidable mistakes.
Learn more about PHP error reporting: PHP The Right Way, Error Reporting.
By design, PHP web applications store executable files with .php file extension in publicly accessible directories. This creates two problems.
- If a user is able to upload a malicious file to the server, they can execute it rather easily and cause damage to the server and application.
- If directory browsing is not intentionally prohibited, a malicious user may be able to access application files containing proprietary or sensitive code.
This is why it is critical to prevent users from uploading and executing PHP code on the server and to ensure directory browsing has been completely disallowed on the server.
Learn more about proper URL routing: How to Implement URL Routing in PHP.
Configuring PHP with Security in Mind
The operation of PHP on a web server is controlled by editing settings in a php.ini file saved on the server. There are quite a few settings in this file that have security implications. Let's look at the most important settings.
Error reporting, which we already touched on briefly, is controlled in php.ini. In general, while developing a PHP application you will want to use the following settings:
display_errors = On display_startup_errors = On error_reporting = E_ALL log_errors = On
The first option will display all errors as part of the program output. This will ensure you see all errors during development. The second option will display errors that occur while PHP is being started on the server. The third option will ensure that all errors are reported and the fourth will log all errors so that you have a record of errors you can review.
When you set up your application on a public-facing server where you do not want to display PHP errors, you can switch over to these settings:
display_errors = Off display_startup_errors = Off error_reporting = E_ALL log_errors = On
This will ensure that all errors are still reported and logged but not displayed on your site.
Disable Dangerous Functions and Features
There are quite a few functions and features in PHP that most web application will not need and should not use. The security of your application can be improved by disabling these features and functions.
file_uploads: set to "0" unless your application lets users upload files.
allow_url_fopen: set to "0" unless you are using it to access trusted resources.
disable_functions: use it to disable dangerous functions that you aren't using such as
session.name: specifies the name used for session cookies and defaults to
PHPSESSID. Make it something unique.
session.cookie_httponly: set it to "1" to make all cookies only accessible via HTTP and protect against XSS (cross-site scripting) attack.
session.cache_expiry: specifies the lifespan of cached session pages and defaults to 180 minutes. Reduce it to a value that makes sense for your application and users, such as "30," for example.
Learn more about securing PHP on web servers: 25 PHP Security Best Practices For Sys Admins.
Dealing with User Data, Authentication, and Session Management
It's one thing to write an application that simply presents data to visitors. However, once you throw users into the equation — users who will need to be authenticated and who will interact with your application data — things get a lot more complicated. Let's look at the key factors to keep an eye on when dealing with user data, authentication, and session management.
User Submitted DataAny data you receive from users should never be trusted. This includes not just obvious user input, but less obvious details that can be manipulated by competent users, such as the data contained in a POST request received along with an HTTP header or data passed back in a cookie. File uploads, in particular, should always be treated as if they may be malicious. Never allow the execution of customer uploaded code. To avoid this, disable PHP execution in directories where user uploads are stored, disallow uploads with filenames that include the .php extension, and assume any file could contain PHP code, even if the extension is not .php.
PHP includes a built in session management function:
session_id, and it is considered to be safe. However, there are a few best-practices you should follow to improve session security:
- Link session IDs to user IP addresses to ensure that session IDs cannot be hijacked.
- Invalidate a session anytime a violation occurs, such as when a second IP address is associated with the session. If that happens, reauthorize the user and reset the session.
- Every time a user's priviledges change, such as when a guest user logs in, reset the session ID.
- Never reveal session IDs. Encrypt them for transmission between the client and browser and don't insert them into URLs.
- Expire sessions after a certain period of inactivity whose duration is selected to match your specific application users' tendencies.
- Use HTTP-only cookies whenever possible and set cookies to expire after an appropriate period of time.
- Never store authentication details such as usernames or passwords in a cookie.
Learn more about user validation and data sanitization: Part 1: PHP Security: User Validation and Sanitization for Beginners and Part 2 of PHP Security: User Validation and Sanitization for Beginners.
Dealing With Malicious Attacks
There are at least five types of attacks PHP applications should be designed to protect against, including SQL injection, shell injection, code injection, cross-site scripting (XSS), and cross-site request forgery (CSRF). You can significantly reduce the risk that one of these attacks will affect your application by taking the following steps.
- The risk of SQL injection exists anytime you're dealing with user data, so you should never use user data when building an SQL string.
- A number of PHP functions such as
systemcan be used to execute shell scripts. Make sure that these dangerous functions have been disabled in php.ini.
- Similarly, the
pre_replacefunctions are dangerous because they accept a string of PHP code and execute it on the server, thus enabling code injection attacks. Disable these functions in php.ini.
- You can avoid cross site scripting attacks by ensuring user input data is properly sanitized by using the
htmlspecialcharsfunction. However, you only have to forget to use this function one time to create a vulnerability, so a better option is to use a PHP templating engine that automatically sanitizes all user input.
- The greatest risk of harm associated with a cross site request forgery (CSRF) attack is that an important action would be forged. To avoid this, assume that all critical actions, such as changing passwords, changing email addresses, updating usernames, changing credit card information, and so forth, may be forged and require reauthentication or email verification to complete these types of changes.
Learn more about malicious attacks and PHP: Understanding PHP Vulnerabilities & How they Originate.
To learn more about the security risks associated with PHP and what you can do to build secure PHP web applications, consult the following resources:
PHP may be the easiest programming language to get started with when learning to build web applications. It's pre-installed on virtually every web server, it's designed specifically for the web, and it includes many built-in features that are only available from other languages if you employ the use of frameworks and libraries. However, PHP is not without its fair — and maybe more than fair — share of security concerns.
Use PHP but know what you're up against before you push your application live on the web. In this PHP security primer, we've covered the critical issues you should be aware of, learn more about, and protect against. However, we've just presented the basics. Study the detailed resources we've linked to, implement what you learn, and you'll be able to build secure PHP web applications.
Further Reading and Resources
We have more guides, tutorials, and infographics related to coding and development:
- C++ Developer Resources: if you'd rather stick to a more traditional language, this page provides you with all the tools you need.
- Composing Good HTML: this is a solid introduction to writing well-formed HTML and using HTML validator software.
- CSS3 — Intro, Guides & Resources: this is a great place to start learning webpage layout.
What Code Should You Learn?
Confused about what programming language you should learn to code in? Check out our infographic, What Code Should You Learn? It not only discusses different aspects of the languages, it answers important questions such as, "How much money will I make programming PHP for a living?"