Securing Your PHP Server in 2018
The start of the new year is a great time to shore up on security. There is much that is needed to minimize the chances of your PHP or Wordpress environment getting compromised by hackers in 2018. Here are some steps excerpted from an article recently published by a security consulting company named Paragon Initiative Enterprises.
Use the Current PHP Versions
Unless you can't help it, you want to be running PHP 7.2 in the year 2018, and plan to switch to 7.3 in early 2019.
PHP 7.2 was released on November 30, 2017.
Currently, only PHP 7.1 and 7.2 receive active support by the developers of the PHP programming language, while PHP 5.6 and 7.0 both receive security patches for approximately another year.
Some operating systems provide long-term support for otherwise unsupported versions of PHP, but this practice is generally considered harmful. In particular, their bad habit of backporting security patches without incrementing version numbers makes it hard to reason about the security of a system given only its PHP version.
Consequently, regardless of what promises another vendor makes, you should always strive to run only actively supported of PHP at any given time, if you can help it. That way, even if you end up on a security-only version for a while, a consistent effort to upgrade will keep your life free of unpleasant surprises.
The state-of-the-art dependency management solution for the PHP ecosystem is Composer. PHP: The Right Way has an entire section dedicated to getting started with Composer which we highly recommend.
If you aren't using Composer to manage your dependencies, you will eventually (hopefully later but most likely sooner) end up in a situation where one of the software libraries you depend on becomes severely outdated, and then an exploit for a vulnerability in older versions starts circulating among computer criminals.
Important: Always remember to keep your dependencies updated as you develop software. Fortunately, this is a one-liner:
If you're doing something particularly specialized that requires using PHP extensions (which are written in C), you cannot install them with Composer. You will also need PECL.
Regardless of what you're building, you will almost certainly benefit from these dependencies. This is in addition to what most PHP developers recommend (PHPUnit, PHP-CS-Fixer, etc.).
Roave's security-advisories package uses the Friends of PHP repository to ensure that your project doesn't depend on any known-vulnerable packages.
composer require roave/security-advisories:dev-master
Alternatively, you can upload your composer.lock file to Sensio Labs as part of a routine automated vulnerability assessment workflow to alert you to any outdated packages.
Psalm is a static analysis tool that helps identify possible bugs in your code. Although there are other good static analysis tools (such as Phan and PHPStan which are both excellent), if you ever find yourself needing to support PHP 5, Psalm is the go-to static analysis tool for PHP 5.4+.
Using Psalm is relatively easy:
# Version 1 doesn't exist yet, but it will one day: composer require --dev vimeo/psalm:^0 # Only do this once: vendor/bin/psalm --init # Do this as often as you need: vendor/bin/psalm
If you're running this on an existing codebase for the first time, you might see a lot of red. Unless you're building an application as large as WordPress, it's unlikely that the effort required to get the tests to all pass will qualify as Herculean.
Regardless of which static analysis tool you use, we recommend you bake it into your Continuous Integration workflow (if applicable) so that it is run after every code change.
HTTPS and Browser Security
Use HTTPS, which should be tested, and add security headers.
In 2018, it will no longer be acceptable for websites to be accessible over unsecured HTTP. Fortunately, it has been possible to get TLS certificates for free, and automatically renew them, thanks to the ACME protocol and the Let's Encrypt certificate authority.
Integrating ACME into your webserver is a piece of cake.
Caddy: Baked-in automatically.
Apache: Soon to be available as mod_md. Until then, there are high-quality tutorials available on the Internet.
Nginx: Relatively straightforward.
You might be thinking, "Okay, I have a TLS certificate. Now I have to spend hours fiddling with the configuration before it's secure and fast."
Nope! Mozilla has your back. You can use the configuration generator to build the recommended ciphersuites based on your intended audience.
HTTPS (HTTP over TLS) is absolutely non-negotiable if you want your website to be secure. Using HTTPS instantly eliminates several classes of attack on your users (man-in-the-middle content injection, wiretapping, replay attacks, and several forms of session manipulation that would otherwise allow user impersonation).
However, while slapping HTTPS onto your server does offer numerous security and performance benefits for your users, you can go a step further by utilizing other browser security features. Most of these involve sending an HTTP response header along with your content.
You want this header because it gives you fine-grained control over the internal and external resources allowed to be loaded by the browser, which provides a potent layer of defense against cross-site scripting vulnerabilities.
See CSP-Builder for a quick and easy way to deploy/manage Content Security Policies.
For a more in-depth analysis, this introduction to Content-Security-Policy headers by Scott Helme is a great starting point.
You want this header because it adds a layer of protection against rogue/compromised certificate authorities by forcing bad actors to publish evidence of their mis-issued certificates to a publicly verifiable, append-only data structure. Learn more about Expect-CT.
Set it to enforce,max-age=30 at first, and increase the max-age as you gain more confidence that this header will not cause service disruptions.
You want this header because it allows you to control whether or not you leak information about your users' behavior to third parties.
Once again, Scott Helme offers an excellent deep dive into Referrer-Policy headers.
Set it to same-origin or no-referrer unless you have a reason to allow a more permissive setting.
You want this header because it tells browsers to force all future requests to the same origin over HTTPS rather than insecure HTTP.
Set it to max-age=30 when first deploying, then increase this value to some large value (e.g. 31536000) when you're confident that nothing will break.
You want this header because MIME type confusion can lead to unpredictable results, including weird edge cases that allow XSS vulnerabilities. This is best accompanied by a standard Content-Type header.
Set to nosniff unless you need the default behavior (e.g. for a file download)
You want this header because it allows you to prevent clickjacking.
Set to DENY (or SAMEORIGIN, but only if you use <frame> elements)
You want this header because it enables some browser anti-XSS features that are not enabled by default.
Set to 1; mode=block
In a similar vein, if you're using PHP's built-in session management features (which are recommended), you probably want to invoke session_start() like so:
session_start([ 'cookie_httponly' => true, 'cookie_secure' => true ]);
This forces your app to use the HTTP-Only and Secure flags when sending the session identifier cookie, which prevents a successful XSS attack from stealing users' cookies and forces them to only be sent over HTTPS, respectively. See secure PHP sessions in this 2015 blog post.
These are great first steps to shore up on security. To further minimize the chances of your PHP or Wordpress environment getting compromised by hackers, you also need to make sure your PHP code itself follows best practices for security. Contact Visual Solutions Inc. visualsolns.com 847.562.5240 if you need help.