This article does not replace a good knowledge of security principles in PHP, but can give you some good advices that really boost security.
There is nothing to copy/paste straight forward to your php files. However if you understand the different points and implement them according to your needs and context, they can give you long-term benefits.
This week’s article will cover PHP configuration, update, code organization and data filtering/escaping.
Configuration and updates
Everything starts with a good knowledge of what you have in your webserver.
Ask yourself a few questions:
– What version of PHP am I running?
– What libraries am I using?
– What code am I including from the outside? Can I trust it?
– What framework am I running and what is its version?
– Is my operating system up-to-date?
If you cannot for sure answer these questions, then you’re missing something.
Having a centralized and up-to-date list of what you are using on your webserver/website is key for your security.
Then, from this list of components, you must be able to answer two questions:
– Do I really need this specific component? If not, remove it. An unused item is an unnecessary risk.
– How do I know when there is an available update for that component? (mailing lists, twitter, RSS feeds…)
Security configuration is an ongoing process that you must perform regularly. This rule always sounds obvious when starting a new project, but is quite rarely applied months after the website is live.
Before we move forward into the different security tips, you must remember on critical proverb: less is more.
Complex security = bad security. Keep it simple, and effective. Also remember that 100% secure does not exist.
Configuring PHP itself is a key step. Having an up-to-date environment is not enough.
Error reporting features are great to understand what’s wrong with your code, but keep it visible to end-users on development/staging environments only!
Your php.ini file allows you to configure three important items:
On a development/staging environment, you can both display and log errors, but you do not want to display them on a production environment. Displaying errors on the production is not very nice, and attackers are also loving them (it gives precious information about your technical architecture).
Logging errors can be interesting on production, but choosing which of them you want to be written in log files is critical, especially on high-traffic website (can lead to huge log files).
This is where the “error_reporting” parameter can help you, by specifying which type of errors you want. Values can be E_ALL (or E_ALL | E_STRCT depending on your PHP version), or for instance E_ALL ^(E_STRICT | E_DEPRECATED | E_NOTICE).
Read more about that parameter: http://php.net/manual/en/errorfunc.configuration.php#ini.error-reporting
Other important php.ini directives should be reviewed. You can go through the following list and review their specificities with the page dedicated to php.ini directives (http://php.net/manual/en/ini.list.php)
Organizing your code properly
Keeping your private code, classes and third party libraries outside of the webroot is a good practice. If for any reason an attacker can retrieve raw files from your webroot, your code will be a little bit more safe (and avoid reverse-engineering).
On the contrary, if classes and libraries are kept in the webroot, for instance www/my-classes/libX1.031/ then attackers might be able to detect which libraries your are using and maybe the versions.
“Filter on input, escape on output”
One principle of security is “Never trust users”. Your legitimate users will probably not try to hack your website, but attackers do. Making the difference between legitimate and evil users is quite difficult, so you have to be cautious with what you receive from them.
Filtering inputs allows you to accept or reject data provided by users. That data can come from url parameters (GET), form values (POST), cookies, http headers.
A good strategy in terms of data validation is to define what you expect from users. It can be a format, or a set of values. Keeping an updated list of data inputs will ensure you keep track of all items you must filter.
From a technical standpoint, filtering can be achieved by using regular expressions (if you are good enough in writing rules) or by using external filtering libraries like “Respect/Validation”.
https://github.com/Respect/Validation (regularly maintained – a few days ago at the time of writing this article).
Filtering data does not mean you are finished with it!
Every bit or user-submitted data, whether directly outputted to the page or firstly stored in a database and then outputted, must be escaped.
PHP native functions exist to perform this type of actions:
htmlspecialchars() – http://www.php.net/manual/en/function.htmlspecialchars.php
htmlentities() – http://php.net/manual/en/function.htmlentities.php
strip_tags() – http://php.net/manual/en/function.strip-tags.php
urlencode() – http://php.net/manual/en/function.urlencode.php
json_encode() – http://php.net/manual/en/function.json-encode.php
mysqli_real_escape_string() – http://php.net/manual/en/mysqli.real-escape-string.php
addslashes() – http://php.net/manual/en/function.addslashes.php
A different option is to use the filter_var function with a given sanitize filter:
The next article, PHP security tricks Part 2 will cover protections against most common attacks (injections, XSS, session hijacking, parameter tampering).