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 article is the third of our series dedicated to PHP security.
The first article “How to protect your website: PHP Security tips and tricks #1” gives you basic guidelines for PHP configuration, updates, data filtering and sanitization, as well as code organization.
The second article discusses protections against known and common attacks.
We will now take a look at file uploads, CRSF, obscurity and cookies.
Protect your cookies
Do not store sensitive information in cookies. Cookies are unsecure by nature, you cannot rely on them to store (temporarily or not) sensitive data.
To protect your cookies against manipulation, one good solution is to sign them, by computing a hash (with a salt), so that the server can verify their content.
The hash must be included in the cookies itself, and retrieved by the server.
File uploads are a very sensitive feature, since they allow users to upload files on your server. Weak implementation may allow attackers to upload PHP scripts on executable folders, giving them the ability to do almost anything.
Since there is no bullet-proof and simple solution, a real defense in depth strategy must be adopted:
- Only authenticated users must be able to upload files
- Limit file upload files size
- Limit file extensions and formats
- Create a .htaccess file in the file uploads parent directory, specifying the list of allowed file extension, for instance with the following rules, depending on your context :
deny from all
<Files ~ “^w+.(gif|jpe?g|png|pdf)$”>
allow from all
- Validate the file type (whitelist specific file types, check the mime-type)
- When saving files,
- Generate the file name randomly, and do not rely on user submitted filename.
- Use unique names
- Verify that the file location is not already used
- Save files outside of the website root folder
- After having saved files, remove execute permission on the file (chmod)
The file max size can be set globally in upload_max_filesize in php.ini. If you want a specific form to allow a smaller file size, you can use the MAX_FILE_SIZE form parameter, but double-check the size with PHP itself, since that parameter can be modified by the user when submitting the file.
Additional checks on the file content:
If you are expecting an image, then you can check the size with getimagesize. If “false” is returned, then the image is not valid.
To go a bit further, the content of the file can be checked against known threats, for instance with ClamAV.
Cross Site Request Forgery (CSRF)
One good rule is to perform all state-changing action via POST requests, instead of GET requests. This will not really remove the risk of CSRF attacks, but will slightly reduce the risk of basic attacks.
To protect yourself against CSRF attacks, you must implement anti-CRSF tokens for your forms. These tokens, stored in the user’s session, will be compared with values returned by the user to validate/reject actions.
If you’re not using a framework that already implements this kind of tokens, you will then have to implement them by yourself, or use third party libraries. The OWASP has a quite good example of CSRF tokens on this page: https://www.owasp.org/index.php/PHP_CSRF_Guard
Read more about CSRF attacks.
Security through obscurity
Obscurity is not a way to prevent attacks from being successful, but can really slow down attackers and hide precious information they are looking for.
You can for instance hide the version of PHP you are using (from headers), by setting expose_php to false in your php.ini.
Another example is a login form: when users submit wrong credentials, there is no need to detail why they could not connect (eg. wrong password). Simply stating that the credentials are not correct is enough, and will therefore not reveal a valid login.
Security is not a one-time and easy thing to implement. First, because it depends on your particular context, but also because things are evolving quite quickly in this field, and new types of attacks emerge over time.
The different tips we provided in these articles are solving major technical vulnerabilities, but not logical flaws. As a functional designer and web developer, you must also ensure that your business logic is bullet-proof, and cannot be circumvented or abused. There is no automated and generic solution for this, apart from reviewing the logic of processes with your team.
Recent development frameworks can also help you implementing security measures, since lot of them include quite easy to use solutions and patterns. However, these security features are also easy to deactivate and any security misconfiguration can have a negative impact. It is therefore important to pay special attention to the documentation detailing how to use these security features. Frameworks are a great way to benefit from the experience of other developers, and to use maintained code.
Now that you implemented these security tips, why not performing a first security audit with our introductory offer?