I know what many of you are thinking! PHP and security? Why bother? Just use another programming language!
Contrary to popular belief, PHP is still a viable language for building web applications. PHP is just another tool that you need to learn to use properly. Let's discuss a few items specific to PHP that will make your site safer.
1. Limit Your Web Root to an index.php and Asset Files
In modern PHP, you will point your web server to a directory with an index.php
file in it that will be the single point of entry for the entire site. The index.php
will load Composer packages and boot your private code to generate the response. It can be tempting to throw other PHP files in the web root for testing. However, you do not want those files to be accidentally committed and expose a problem in your app. In addition, no configuration files should go in the web root because the web server can deliver them publicly. The only static files that should be in your web root are JavaScript, CSS and image files.
2. Turn Off Display Errors
You can set PHP to display errors that occur during execution with a php.ini
directive called display_errors
. The errors displayed can leak important information about your app including secrets and SQL queries. It is important to turn them off in production. In your php.ini
file, set display_errors = Off
and display_startup_errors = Off
. To still capture the errors for debugging, turn on log_errors = 1
and error_log = /var/log/php-error.log
. You can set the error log to any file path or even set it to an OS level log service.
3. Use password_hash to Store Your Passwords
It is common knowledge to never store passwords in plain text. However, many frameworks still use insecure hashing algorithms for converting passwords (I am looking at you WordPress). You may see some legacy articles recommending using the md5
or hash
function to hash passwords in PHP. Do not use them! The best way to hash a function in PHP is to use the password_hash
function. You can use it like this:
<?php
$hash = password_hash('iamapassword', PASSWORD_DEFAULT);
if (password_verify('iamapassword', $hash)) {
echo "The hash matches!\n";
}
The password hash function takes the plain text password and an algorithm type (PASSWORD_DEFAULT
is a safe choice). The function returns the hashed password which you can use in the password_verify
function later when the user is logging in. Password verify returns true or false depending on if the hash matches the submitted password. In case you see an article recommending salting your passwords, do not worry about salts with password_hash
. The function salts the password automatically for you.
4. Encrypt All Communication
In your PHP app, you will often have to communicate with other services or storage mechanisms. It is important that you always use encrypted connections to the services. When using curl
or soap
, always use https
URLs to APIs to verify the data in transit is encrypted. In addition, if you are using FTP, make sure you use some form of secure FTP, either FTPS or SFTP. If you don't use any kind of secure transmission, then you might leak user data over the network activity. Using TLS also verifies the URL is what it claims to be which protects you from sending data to a bad actor.
5. Use a Template Framework
PHP itself is often used as the template language embedded in HTML files. However, PHP does not escape output by default. Escaping prevents a bad actor from embedding malicious JavaScript in user controlled forms or pages. Consider using a custom template solution like Twig. Twig automatically escapes all output using its template syntax which protects you from forgetting to escape user data.
There is a lot more to creating a secure website than these tips, but hopefully they contribute to the overall security of your codebase. I have written about other ways to secure your website in Four Tips for a More Secure Website. Check it out if you want to learn more!
Top comments (18)
As an addendum, I'd add: "Learn about SQL injection." This is still the most common attack vector against a web application. Most modern frameworks will protect you from this, but you should absolutely know what it is, how it works, and how to avoid being open to it.
It's so sad that it still is. I mean it's a solved problem, just use prepared statements and you are save!
Yes, and you can't imagine how many website are vulnerable to this kind of attack and XSS and CSRF as well.
Even if they are well known and have great mitigation techniques.
Follow secure tips like the ones described here and the OWASP documents and you are good to go.
Yes ! I recommend this short but useful resource, also the same site have a good resource about PDO
And better read this: phpsecurity.readthedocs.io/en/latest/
PHP7 is probably the best web language in existence today.
In the world of Python and Ruby, building websites from the ground up is tiresome because neither Python nor Ruby was originally created to build websites. As a result general-purpose frameworks such as Django and Ruby on Rails quickly became popular for building websites in these languages.
PHP on the other hand was created in the beginning by Rasmus Lerdorf as a set of tools written in C that would enable you to easily and quickly develop dynamic HTML.
Great post Andrew! I think these tips are great as a checklist of sorts to go through when developing/deploying a new PHP site such as turning off verbose errors etc. but I think it's just as (if not more) important that as developers we understand the ways in which our applications and websites could be attacked.
Using frameworks is a good way to protect against these sorts of exploits however it is much better if the dev understands the way in which the framework is protecting them as it is still rather easy for an uninformed dev to code around the protections most modern frameworks offer (raw DB queries etc.) without realising that they may be compromising the security of their application.
Check out this course: hacker101.com/ I completed it recently and it truly does open your eyes up to some of the super complex ways people are able to exploit websites.
You should also use password_needs_rehash once you verified a password, this ensures that you keep the most up-to-date hashing algorithm.
Another development secure tip is use env variables to config
I would add another one: Use a well-supported Web Framework
Phew, I had it all ;)
It's good
I'd like to add one more, use security tokens. A security token makes sure the client did sent a certain request to your application. I'm maintaining the following open-source PHP package: CSRF Protection where you can use tokens and validate them without too much boilerplate code.