Introduction to PHP Security – Part 1

It is a question that has daunted software engineers for decades: how secure is my software application? Modern web application development has evolved to a point where one can build and launch an entire product or company revolved around a full-fledged software-as-a-service. The only interface to your product is the UI provided via a browser, mobile application, or the data exposed by your web service API. Unfortunately, as these modern software media continue to evolve into more sophisticated platforms, so do the areas in which your product and your data become exposed to potential security risks, criminal intrusions, and data theft.

We’ll explore in this blog frequent channels of attacking and exploiting a PHP application. This blog is by no means an official guide to the security of your application, and you should always consult with your team of security experts on the best practice for your application environment.

Common Attacks

For starters, we’ll cover some of the most common attacks that you should be aware of. Almost all modern frameworks, libraries, and extensions have built-in mechanisms to patch these popular methods of attacks, but we’ll cover them nonetheless. These attacks are extremely simple to do and very easy to thwart, but they are very damaging if left exposed to the public.

Cross-Site Scripting (XSS)

All the data that you present to your users are not entirely hosted by you, contrary to popular belief. Modern web applications are extremely dynamic and pull data from various sources. In some instances, your site could provide the ability for a user to leave comments via a form. From inside that form, a hacker could paste a <script> tag pointing to a malicious script on another remote server.

This comment is then saved in the database, retrieved again for another user, and displayed in that user’s web browser. Because the attack is HTML, the hack does not display when rendered in the browser. However, if you use the view-source command on the page, you’ll easily see the embedded Javascript that was inserted and executed in your browser and every browser of the users of the site. Potentially, millions of your customers could be compromised by running unknown Javascript that is served by your application but points to another remote file controlled by hackers!

Further, the hacker can place more than just a <script> tag. XSS involves <iframe>, <body>, and even <img> exploits. How do you avoid this? You sanitize all the data that you receive from users!

Common sanitation techniques include strip_tags(), htmlspecialchars(), and other data filtering techniques.  

SQL Injection

This exploit is creative and, frankly, deadly to your database. Imagine, for instance, that you are passing information from one page to another via hidden fields in a form.

In this case, you are accessing $_POST[‘user’], and the value is 23 and $_POST[‘password’]. Then, you move on to the database to perform a SELECT from your user table where user = 23. This particular attack overrides the SQL and inserts an additional statement so that your query returns true. For example, where you normally perform this:

SELECT user_id FROM user WHERE user_id = ‘23′ and password = ‘bla’

this hacker could override that by making you execute this:

SELECT user_id FROM user WHERE user_id = ‘23′ and password = ‘bla’ OR ‘true’ = ‘true’

The query above can run successfully and return true, even though the password is incorrect, causing your hacker to gain access by only knowing the user_id and not knowing the password at all!

To learn how to avoid database hacks, you can scroll down to the Database section (below).

Security Best Practice

OK, we’ve covered a couple of the most common attacks look like. Let’s dive into software development best practices and how they can help protect you from being vulnerable to attacks.

Security is a moving target. There is no perfect method of protecting yourself from the infinite exploits that could potentially exist. What does one do in this case in order to avoid being compromised? There are some basic best practices that should be implemented in your PHP environment.

Keep your PHP Upgraded

Always keep your PHP version up-to-date. I cannot stress this enough. You would probably be shocked at the amount of PHP users today who are running vulnerable versions of PHP, going as far back as PHP 4! Even within the PHP 5 series, always keep up-to-date with the latest version, and keep in mind that the PHP group does drop support and will end-of-life a version, regardless of who is running it. This means your PHP version could be outdated and vulnerable.

Keep SSL on at all times

There used to be a time when SSL was only used for when dealing with financial or health records. In other words, SSL was used when federal regulatory bodies required it. However, best practice is beginning to dictate that SSL always be turned on at all times throughout the lifetime of a customer session. The threat to security has unfortunately become so prevalent that even the most basic of requests can come under threat. For this reason and others, turning on SSL at all times has become a common practice in most web applications.

Validate everything that you collect and that is sent to you

All information that is passed to your application is suspect. There is no exception to this rule. Even if you receive this information from a third-party web service API, there is no guarantee that their data is not contaminated. You cannot vouch for the security of another company, so it is probably best to practice good data validation against information received from the outside world.

This information can be in the form of input from your users, partner access to your web service API, or perhaps even local files you are opening with PHP to parse through. Before any data is processed, saved to a database, or returned to your customers, you should always run the data through basic sanity checks.

Also, keep in mind that the session data that you set can be jeopardized. For example, when you set a cookie value on the client side, that value can be manipulated; so, the next time you access it, you should validate that data. You probably shouldn’t see sensitive information in your cookies, but just in case, verify the data, too.

Take a look at the filter_var() and filer_input() functions and see how you can fit it into your sanitation workflow. Configure your php.ini for optimal security. Your php.ini file may contain serious security flaws if you do not configure your environment correctly. I wrote another blog piece on this topic that you can read. In that blog post, I have a section that covers a basic introduction to security, but also covers other basic declaratives that you should be aware of.

Follow proper Error Reporting practices

The general rule when it comes to error reporting is: report everything in development, display nothing in production.

This means that, while you are in development mode, you want to be aware of all potential issues with your PHP application – including Notices, Warnings, and, of course, Errors. However, in production, you never want error information to be displayed to your visitors. Not only will you avoid upsetting your customers, but you’ll also avoid displaying secure information that could be used against you if it fell into the wrong hands.

Configuration Files – Keep them safe and hidden

All modern frameworks and web applications require configuration files. These are the files that contain access information, connection info, passwords, database connectivity, and environment-specific variables. Obviously, this file is extremely sensitive and should never be compromised. You do not want these files in your public web directories. Configuration files should always be at least one directory above your public web folders and accessed from within the application itself by a front controller or the framework.

Front Controller Method – Keep PHP files private

This approach is possible with almost all modern PHP frameworks. The only file that should be exposed in your public web root folder is your front controller or index.php. Your front controller then instantiates your framework object, dispatches all requests to the internal router, and includes the necessary framework files by going one level down. This way, you never have any of your application files exposed to the Internet and only have a single point of entry that you can lock down to make more secure.

Database Abstraction Libraries are your friend

If you are using a framework, you are probably using a database abstraction layer. Alternatively, at the least, you could be using MySQLi or PDO. Regardless of what method you use to interface with your database backend, all data should be sanitized before being inserted into your database. Specifically, by using prepared statements, you ensure that your database libraries perform all the tedious work of extracting and removing potentially malicious data hidden inside your inputs. Remove unnecessary PHP extensions. You do not want to have more extensions than you need. Perform a quick phpinfo() on your PHP runtime to find out how many extensions you have loaded and remove all the extensions that you do not need. By including extensions that you do not need, you are introducing potential performance overhead and security risks. The more variables you can remove from the equation, the less you have to worry about. It is just good practice, in general, not to load more extensions than necessary.

Conclusion

This list barely scratches the surface in regards to PHP security. There are more advanced topics, including proper password hashing and encryption techniques, proper session and cookie management, file and permissions techniques, web server and firewall configurations, and more. I hope this post, at least, provides a basic introduction to PHP security topics as a starting point in securing your application and your customer data.

© xkcd.com

Interested in gaining end-to-end visibility of your PHP application? Check out a FREE trial today!  

Understanding php.ini

Introduction

Your php.ini file provides a considerable amount of power over the behavior of your PHP application ecosystem. Let’s jump into some of the most common declaratives and discuss how they impact your application performance and behavior. I won’t go into an explanation of each setting that is available, but I’ll cover the fundamental options that you should be aware of. Please keep in mind that changing any of the settings on in your php.ini can and may very well change the behavior of your application, whether positive or unfavorable. Please use caution when adjusting your settings, consult with your team, do your research, understand the implications, and, of course, test, test, and test again before deploying anything into production!

What is php.ini?

As with all complex software applications, the behavior of your PHP runtime can be configured using a php.ini file. This is the file that instructs how PHP should behave before executing your PHP application code. Your php.ini is ordinarily located in the ./lib directory of where you installed PHP. For example, if you installed php in /usr/local/, you can find the php.ini in /usr/local/php/lib.

Alternatively, you can find it yourself by turning to our all-helpful-utility-function:

<?php phpinfo(): ?>

Look for the line “Loaded Configuration File:”; this is the path to where your php.ini file resides.

I’ve organized this post into the following categories: security, memory, and performance. If you’re interested in only one aspect, feel free to jump to that category.

Basics

You can edit your php.ini file directly. However, depending on how your environment is set up, you can share the same PHP runtime but have different settings per application. Specifically, if you’re running virtual hosts with Apache, for example, you configure your server to allow a .htaccess file per application directory with specific php declaratives to override the default php.ini settings. Furthermore, you can also override php.ini settings from within the application itself in-flight via ini_set(). Keep in mind, ini_set() is only used during the lifetime execution of the script and will not persist its value permanently.

What does php.ini affect? It affects everything. Well, almost everything: you may have additional config files (e.g. apc.ini) for various libraries and tools you’re using (check with your system administrator if you’re trying to configure something that is not located within your php.ini). Generally speaking, your php.ini holds the keys to settings that impact your application security, speed, and user experience. We’ll cover some of the basics and understand why they’re important, and dive deep into how you can optimize your environment to reach your objectives. We’ll begin with a couple simple examples: short_open_tag and error_reporting.

short_open_tag

This tag is one of my favorites – it allows you to use shorthand <? instead of <?php when opening PHP code. With this shorthand, you can trim your PHP code in your HTML when you need to do something like this:

Hello, <?=$firstname>!

If you use PHP in your HTML, you can trim embedded code to make it become more readable.

error_reporting

PHP has multiple levels of errors: E_ALL, E_NOTICE, E_WARNING, etc. This directive allows you to decide the error pain threshold. You want different levels in your various environments, but try to be the most strict in development and the least in production.

A common trick that some developers are unaware of is to convert your errors into exceptions. Using this method, you can “catch” your errors and “handle” them as you normally would. This is made possible by using the ErrorException class with the set_error_handler() function. Furthermore, use this setting in conjunction with display_errors when configuring how to handle displaying errors in production. Tuning this directive is best when optimized with complimentary settings.

Note: setting error_reporting to E_ALL or -1 will show all possible errors, but this depends on your version of PHP. Be sure you understand the differences.

Security

register_globals

This is reasonably one of the most dangerous directives in PHP. When this setting is turned on, it allows input data – such as POST or GET – to be accessible via the $_REQUEST variable. Imagine, for instance, an application setting a user type as “admin” in a cookie variable and that value is accessed via $_REQUEST[‘access_level’]. If a malicious user were to pass ‘?access_level=admin’ in the URL, $_REQUEST could potentially read that as the access level. This directive went from ON to OFF by default in PHP 4.2 and removed it in 5.4, so the industry has heavily matured away from this dangerous practice. Nonetheless, this is something that you should be aware of in legacy code.

magic_quotes_gpc

I won’t expand too much on this as this has been deprecated since PHP 5.4, but it is something you should note in legacy code. This declarative automatically adds a ‘\’ to help escape special characters. Unfortunately, this created a nightmare when you have addslashes() and stripslashes() throughout your code, and you’re ripping your hair out trying to keep track of when and how PHP is magically manipulating your data (pun intended). In short, turn this off, and forget it ever existed. You should manually escape input from public variables via other means when needed.

expose_php

When set to ‘On’, this will expose to the public that you’re running PHP and the version number via X-Powered-By: in the HTTP header. If this is turned on, you’re exposing yourself to security threats that may be exposed by your version of PHP or exposing that you’re running PHP itself. Keep it off and don’t let the public know what you’re running under the hood. The less that hackers know about your environment, the less of a strategy they have on how to attack you.

Memory

output_buffering

This setting controls how your HTML is sent to the browser. When turned off, the HTML is sent to the browser in pieces as PHP combs through the execution sequence and stitches your dynamic and static content together. When turned off, your HTML is turned into a single variable and sent to the browser in one giant piece. While you’re piecing your HTML together, the bits live in a buffer “zone”, and you’re still provided access to the data before it’s finally sent to the browser. Thus, if you experience an error during execution, you can choose to send the user a friendly error message instead of a half interpreted broken HTML page. This setting is advantageous because it allows you to manipulate your HTML the same way you would manipulate a string in PHP, so you have greater control. In the MVC paradigm, you can benefit from stitching together partial modular components that put together the final view.

max_execution_time

When a request comes in and PHP begins to execute your code, it takes time to complete the transaction. In some situations, you may have an execution stack that takes too long. This can happen for various reasons such as bad code, a hung database, or slow responses from third-party web service APIs. As a failsafe, PHP allows you to mitigate this risk by capping the execution time to whatever value you set here. If your threshold is high, your customers will naturally suffer from poor performance, regardless. I would recommend setting this value to enough time to reasonably capture diagnostic data for the holdup, but not too long to where the customer has to wait for minutes for a page to load because, they won’t, of course. If you’re finding that your code is executing for too long, it may be time to collect diagnostic data with the AppDynamics for PHP agent.

Note: You can set this value to 0 for infinite time, but that is not a good idea in production for obvious reasons. Do not do this. There is a native function that allows you to override this value. If you need to override it in certain scenarios, you may explore the set_time_limit() function which effectively performs the same function ad hoc.

memory_limit

In addition to the amount of time your PHP script takes to execute, there is also an amount of memory that your script will consume. This setting will set a maximum allowed quantity of memory to be allocated to the script so that if your script is running havoc, you can cap it and protect your server resources.

Note: I’ve seen certain cases where memory_limit is set to -1, which allows for unlimited memory. This is also, of course, a bad idea. Use the -1 setting only in development and testing environments, if and when needed.

upload_max_filesize

This declarative allows for the maximum file size allowed to be uploaded from the server. As a matter of good practice, I think the jury has already ruled on this one: don’t rely on the server alone to verify file size; check this first on the client side. Historically, a form would upload an entire file to the server before it was accepted or rejected. This means a user could upload a 500mb file, tie up server resources, be at the mercy of their Internet upload speed, and then finally have their inputs rejected. Imagine if their form failed validation because of an improper email address: they would have to repeat the process. A good programmer caches the uploaded file on the server side so as not to wait for the file to upload again, but if the user uploads a different file, the wait time will have to repeat. This is a dangerous practice and a potential loophole for hackers too.

post_max_size

This sets the maximum size of the entire POST data being sent. The difference between this and upload_max_filesize is that this regulates the whole size of the data being sent to the server, whereas the latter governs the size of an individual file. Adjust this accordingly.

max_input_time

This is the maximum amount of time a script is allowed to parse input data, whether POST or GET. Essentially, this is the maximum amount of time you’re allowing an upload to complete. For example, if you set this to 60, the upload must finish within 1 minute. This is a challenge for users with slow Internet connections, but the advantage for you is to make sure your server resources have a fail-safe measure to avoid being tied up.

include_path

This defines all the various system paths that PHP will need to look when you include files in PHP (e.g. require(), include(), etc.). The shorter this list, the better your performance since you won’t have to spend so much time searching for files.

Conclusion

In addition to the php.ini declaratives mentioned in this post, there are dozens of other declaratives that can help further fine-tune and tailor your PHP ecosystem to find the perfect balance of security, performance, scalability, and optimal user experience. This is only a mere introduction into the capabilities afforded to you by your php.ini settings and meant to get you to become comfortable with the various configurations that could impact you in critical ways. However, when you configure your PHP, always remember that your goal is to strike the right balance without sacrificing the end-user experience. Application performance is a moving target, and the better you’re aware and equipped with the means of reaching an optimal user experience, the happier you and your customers will be.

Check out AppDynamics for PHP, download a FREE trial today!