This security checklist aims to give developers a list of PHP security best practices they can follow to help improve the security of their code.
Always Perform Context-Aware Content Escaping
Deprecate Features and Libraries When They’re No Longer Used
Stay abreast of the packages and language features that you’re using. If a language feature planned to be deprecated, such as Mcrypt, or a third-party package becomes abandoned, then start planning to replace it with an alternative.
Disable Unsafe and Unrequired Functionality
Some PHP installations can be preconfigured with unsafe and unrequired functionality already enabled. Ensure that you review your PHP configuration and
phpinfo() output for any unsafe settings and disable or limit them.
Disable or Limit Program Execution Functionality
Program execution functionality, such as exec, passthru, shell_exec, and system, can leave open the possibility for users to be able to execute arbitrary code on your system and shell injection attacks. Disable this functionality if it’s not explicitly needed.
Don’t Cache Sensitive Data
When you cache data to speed up your application, such as database requests, ensure that sensitive data isn’t cached.
Don’t Implement Your Own Crypto
Unless you’re a security expert—and even if you are—never implement your own crypto. This is a common cause of security errors, as too few eyes have had a chance to review the code. Instead, use a publicly reviewed, critiqued, and tested library, such as Libsodium in PHP 7.2.
Filter File Uploads
If malicious files can be uploaded and executed by users, then the application, its data, or the supporting server(s) can be compromised. Ensure that PHP’s file upload configuration is correctly configured to avoid these attacks from occurring.
Filter and Validate All Data
Regardless of where the data comes from, whether that’s a configuration file, server environment, GET and POST, or anywhere else, do not trust it. Filter and validate it! Do this by using one of the available libraries, such as zend-inputfilter.
Integrate Security Scanners Into Your CI Pipeline
Security scanners can help to detect questionable code and code that contains obvious security defects. Continuous Integration (CI) tools can use these scanners to test your code and fail the build if the scanner meets or surpasses acceptable thresholds.
Invalidate Sessions When Required
Keep All Dependencies Up to Date
Most PHP code relies on external, third-party dependencies. However, these need to be kept up to date, wherever possible, to ensure that any bug and security fixes are available to your code. Ensure you’re using Composer as your dependency manager and keep up to date with all of your dependencies.
Make sure permissions on filesystem are limited
PHP scripts should only be able to write in places you need to upload files of specifically write files. This places should not be anywhere a PHP script can be executed by the server. Else, it open the way for an attacker to write a PHP file somewhere and to run arbitrary PHP code.
Never Display PHP Errors and Exceptions in Production
While errors, warnings, and exceptions are helpful during development, if displayed in production or any other public-facing environment, they may expose sensitive information or intellectual property. Ensure that this information is logged internally, and not exposed publicly.
Never Store Sensitive Data in Session
Never Store Sessions in a Shared Area
It has been common, when using shared hosting providers, for PHP to be automatically configured to store sessions on the filesystem, in the same directory. Never do this. Always check your configuration and store session information in a private location, accessible only by your application.
Perform Strict Type Comparisons
If weak type checking is used, such as with the
== operator, vulnerabilities can occur due to the often peculiar ways that PHP converts types. These include 1.14352 being converted to 1, strings converting to 1, “1is this true” converts to true, and so on. This is because according to the manual:
By default, PHP will coerce values of the wrong type into the expected scalar type if possible.
Use strict type checking to ensure that when comparing two items that they are of the same type. And in PHP 7.1, use
open_basedir directive limits the files that PHP can access to the filesystem from the
open_basedir directory and downward. No files or directories outside of that directory can be accessed. That way, if malicious users attempt to access sensitive files, such as
/etc/passwd, access will be denied.
Store Passwords Using Strong Hashing Functions
Ensure that all passwords and other potentially sensitive data are hashed, using robust hashing functions such as bcrypt. Don’t use weak hashing functions, such as MD5 and SHA1.
As of PHP 7.2, older encryption libraries have been deprecated, such as Mcrypt. However, PHP 7.2 supports the far better Libsodium library instead. Now, out of the box, developers can make use of modern cryptography with next to no knowledge of cryptography.
Use Microframeworks Over Monolithic Frameworks
Microframeworks contain as few services, libraries, and configurations as possible, while monolithic frameworks contain a vast array of services, libraries, and configurations on the off-chance that at some stage you will use them. Reduce the possibility of security defects by using a microframework if at all possible.
Use PHP 7!
PHP 7 includes a range of built-in security-specific improvements (such as libsodium in PHP 7.2) and deprecates older, insecure features and functionality. As a result, it is far easier to create more secure applications with PHP 7, than any previous version of PHP. Use it whenever possible.
Use Parameterized Queries
To avoid SQL injection attacks, never concatenate or interpolate SQL strings with external data. Use parameterized queries instead and prepared statements. These can be used with vendor-specific libraries or by using PDO.
Use Secure Session Settings
When using sessions make sure that you configure them to be as secure as possible to prevent as many attacks as you practically can. This includes locking a session to a domain or IP address, don’t permanently store cookies, use secure cookies (sent over HTTPS), use large session
Use a DAST
A DAST is a Dynamic Application Security Tester (or testing service). A DAST searches for weaknesses and vulnerabilities in running applications. But the number of false positives and false negatives makes it hard to trust.
Use a Package Vulnerability Scanner
As modern PHP applications use a wide variety of external dependencies, you need to be sure that you’re not using any with known vulnerabilities. To do that, ensure that you’re regularly scanning your source code with a vulnerability scanner.
Use a Reputable ACL or RBAC Library
Use a SAST
A SAST is a Static Application Security Tester (or testing service). A SAST scans source code looking for vulnerable code or potentially vulnerable code. But the number of false positives and false negatives makes it hard to trust.
Use an ORM
Whitelist, Never Blacklist
Never attempt to filter out unacceptable input. Just filter for only what is acceptable. To attempt to filter out anything that is unacceptable leads to unnecessarily complicated code, which likely leads to defects and security flaws.
Check Your SSL / TLS Configurations
Connect to Remote Services With TLS or Public Keys
When accessing any database, server, or remote services, such as Redis, Beanstalkd, or Memcached, always do so using TLS or public keys. Doing so ensures that only authenticated access is allowed and that requests and responses are encrypted, and data is not transmitted in the clear.
Do Not Store Sensitive Data In Configuration Files
Do not send sensitive information in headers
By default PHP will set his version number in the HTTP headers. Some frameworks may do the same as well.
Log All The Things
Make Requests Over HTTPS Wherever Possible
To avoid Man in the Middle attacks, to protect the integrity of your site, and privacy of your users, you need to make all requests over HTTPS—especially requests involving sensitive data, such as logins, password and account changes.
Rate Limit Requests to Prevent DDoS Attacks
To stop users attempting to perform brute force login attacks and overwhelm your forms, use tools such as Fail2Ban to throttle requests to acceptable levels.
Renew Your Certificates On Time
Using SSL certificates is essential to encrypting your web site or application’s traffic with HTTPS. However, they do expire. Ensure that you’re updating your certificates before they expire.
Have a Content Security Policy
Whether you have a one page, static website, a large static website, or a sophisticated web-based application, implement a Content Security Policy (CSP). It helps to mitigate a range of common attack vectors, such as XSS.
Send All Available Security Headers
There are several security headers that you can use to make your websites and web-based applications more secure, for minimal effort. These include HSTS, X-XSS-Protection, X-Frame-Options, X-Content-Type-Options, and a Content Security Policy. Ensure that they’re being configured correctly and sent in your request responses.
Monitor your application security
Monitor your application security for suspicious behaviors and attacks. Knowing when your application is starting to get attacked is key to protect it before it’s too late.
Protect your sensitive data in real-time
Code vulnerabilities will always exist. Make sure you have a security solution in place that detects and blocks OWASP attacks but also business logic threats.
Protect your users against account takeovers