The year 2018 is approaching, and techies - in particular, web developers - must reject many of the old techniques and beliefs in the development of secure PHP applications. This is especially true for anyone who does not believe that such applications are possible at all.
This guide is an addition to the PHP: The Right Way e-book with a strong emphasis on security, and not general PHP programming issues (such as code style).
In short: nothing can be done, but in 2018 you will use PHP 7.2 , and in the beginning of 2019 plan to switch to 7.3.
PHP 7.2 released November 30, 2017
At the time of this writing, only PHP 7.1 and 7.2 are actively supported by language developers, and for PHP 5.6 and 7.0, security patches will be released for about a year.
Some operating systems have long-term support for PHP versions that are no longer supported, but this is generally considered to be a bad practice. For example, backporting security patches without incrementing version numbers makes it difficult to evaluate the security system for PHP only.
Accordingly, regardless of the promises of vendors, always try to use only an actively supported version of PHP, if possible. Even if you spend some time working with a version for which only security patches are released, regular version updates will save you from many unpleasant surprises.
In short: use Composer.
Composer is a masterpiece dependency management solution for the PHP ecosystem. In PHP: The Right Way, a whole section is devoted to getting started with Composer , we highly recommend reading it.
If you do not use Composer to manage dependencies, then sooner or later (hopefully late, but, most likely, early) you will find yourself in a situation where one of the libraries you depend on is very outdated and criminals will actively exploit vulnerabilities in old versions.
Important: Do not forget to update your dependencies as software is developed. Fortunately, this can be done in one line:
composer update
If you are doing something special that requires the use of PHP extensions (written in C), then you cannot install them using Composer. You will also need a PECL.
Regardless of what you create, surely these dependencies will be useful to you. This is in addition to what most PHP developers recommend (PHPUnit, PHP-CS-Fixer, etc.).
The Roave security-advisories package uses the Friends of PHP repository so that your project does not depend on any packages with known vulnerabilities.
composer require roave/security-advisories:dev-master
Or you can upload your composer.lock
file to Sensio Labs as a standard automated vulnerability assessment procedure to receive alerts for any obsolete packages.
Psalm is a static analysis tool that helps identify possible bugs in your code. Although there are other good tools (for example, the wonderful Phan and PHPStan ), but if you need support for PHP 5, then Psalm is one of the best static analysis tools for PHP 5.4+.
Using Psalm is simple:
# 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 this is the first time you apply this code to an existing database, you will see a lot of red marks. If you do not create a WordPress-scale application, then it is unlikely that you will have to perform the Hercules feat in order to pass all these tests.
Regardless of which static analysis tool you choose, we recommend integrating it into the continuous integration workflow (if possible), so that the tool runs after each code change.
In short: HTTPS to test , and security headers .
In 2018, sites will no longer work via unsecure HTTP. Fortunately, you could get TLS-certificates for free and automatically update them thanks to the ACME protocol and the certification company Let's Encrypt .
Integrating ACME into your web server is a couple of trivia.
You might think, “Okay, I have a TLS certificate. Now we need to spend several hours searching for configurations to make the site safe and fast. ”
Not! Mozilla will help you . To create the recommended cipher suite for your audience, you can use the configuration generator.
HTTPS (HTTP over TLS) is completely uncontested if you want to make your site secure. The use of HTTPS instantly eliminates several types of attacks on your users (implementation of man-in-the-middle content, interception of data, replay attacks and manipulation of sessions for the sake of user substitution).
Although the use of HTTPS on your server has many advantages in terms of security and performance, you can go even further and use other browser security features. Most of them involve sending HTTP response headers with content.
Content-Security-Policy
Expect-CT
Expect-CT
: https://scotthelme.co.uk/a-new-security-header-expect-ct/ .enforce
, max-age=30
, and when make sure that the header does not interfere with the service, increase the max-age
.Referrer-Policy
Referrer-Policy
headers .same-origin
or no-referrer
until there is no reason to transmit more information.Strict-Transport-Security
max-age=30
, and then increase the value (for example, to 31536000
), when you are sure that nothing will break.X-Content-Type-Options
Content-Type
.nosniff
, unless you need the default behavior (for example, to download files).X-Frame-Options
DENY
(or SAMEORIGIN
, but only if using <frame>
elements)X-XSS-Protection
1; mode=block
1; mode=block
Similarly, if you use the built-in PHP session management properties (which is recommended), you may want to call session_start()
:
session_start([ 'cookie_httponly' => true, 'cookie_secure' => true ]);
Then, when sending credentials, your application will use only secure HTTPS flags, which will prevent successful XSS attacks by stealing user cookies, they will be sent only via HTTPS. A couple of years ago we already wrote about secure PHP sessions .
Someday in the future you will be working on a project that uses CDNs to unload traditional Javascript / CSS frameworks and libraries into a central location. Not surprisingly, security experts predicted an obvious problem: if many sites use CDN to provide part of their content, then cracking the CDN and swapping data will allow embedding arbitrary code on thousands (if not millions) of sites.
Therefore, we invented the integrity of subresources (subresource integrity).
Sub-Resource Integrity (SRI) allows you to pin a hash of the contents of the file, which the CDN should provide you. The current implementation of SRI allows only cryptographic hash functions to be used, so attackers will not be able to generate malicious versions of the content, resulting in the same hashes as those of the original files.
Real-world example: Bootstrap v4-alpha uses SRI in the sample code of their CDN .
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous" /> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous" ></script>
Web developers often set the target
attribute to hyperlinks (for example, target="_blank"
to open a link in a new window). But if you don’t also pass the rel="noopener"
tag, then let the landing page take control of the source page .
Don't do that
<a href="http://example.com" target="_blank">Click here</a>
This will allow example.com
to gain control over the current page.
Do this
<a href="https://example.com" target="_blank" rel="noopener noreferrer">Click here</a>
In the new window opens example.com
, but does not gain control over the current window.
If security software is new to you, you can start by introducing A Gentle Introduction to Application Security.
Many security experts from the very beginning draw the attention of developers to resources like OWASP Top 10 . But many common vulnerabilities can be considered as special cases of the same high-level problems (code / data is not adequately separated, erroneous logic, unsafe operating environment, broken cryptographic protocols).
We believe that if we instill in the safety of the neophytes a simpler, more fundamental understanding of security problems and their solutions, this will help improve the security situation in the long run.
Read more: Preventing SQL injections in PHP applications
If you write SQL queries yourself, make sure that you use prepared statements (prepared statements) and that any information provided by the network or file system is passed as parameters, and not concatenated into a query string. Also make sure you avoid emulated prepared expressions.
The best choice is EasyDB .
DO NOT DO THIS:
/* : */ $query = $pdo->query("SELECT * FROM users WHERE username = '" . $_GET['username'] . "'");
Do this:
/* SQL-: */ $results = $easydb->row("SELECT * FROM users WHERE username = ?", $_GET['username']);
There are other layers of abstractions in the databases that provide an equivalent level of security (EasyDB uses PDO under the hood, but by all means tries to turn off the emulation of prepared expressions in favor of real prepared expressions to prevent problems). As long as user input does not affect the structure of requests (this also applies to stored procedures), you are safe.
Read more: How to safely allow users to upload files
Accepting user files is risky, but it can be done safely by taking a number of precautions. In particular, close direct access to downloadable files so that they cannot be executed or interpreted.
Downloaded files must have read-only or read-only or write attributes and never be executable.
If your site has a root directory for documents /var/www/example.com
, then you should not store the downloaded files in /var/www/example.com/uploaded_files
.
It is better to store them in a separate directory, to which there is no direct access (for example, /var/www/example.com-uploaded/
), so that they are not randomly executed as server scripts and do not open the door to remote code execution.
A cleaner solution is to move your root directory for files one level down (i.e., at /var/www/example.com/public
).
Another problem with downloadable files is related to their safe download .
image/
prefix in the MIME type .X-Content-Type-Options
..php
or .phtml
file can execute arbitrary code by accessing the file directly in the browser and get full control over the server. Be careful.Read more: Everything you need to know about PHP cross-site scripting prevention
In an ideal world, preventing XSS would be as easy as SQL injection. We would have an easy-to-use API for separating the structure of a document from its contents.
Unfortunately, in the real world, most web developers generate long HTML and send it in an HTTP response. This is not only characteristic of PHP, it’s just the reality of web development.
Closing XSS vulnerabilities is a completely solvable task. However, the contents of the browser security section unexpectedly gaining more importance. In short:
echo htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
- this is a safe and effective way to stop all XSS attacks on a page using UTF-8, but all HTML will be prohibited.Cross-site request forgery is a type of attack with delegate substitution: you can trick the user browser and force it to execute a malicious HTTP request with elevated user privileges.
In general, this problem is easily solved:
We wrote the Anti-CSRF library, which goes even further:
If your framework does not care about CSRF vulnerabilities, then use Anti-CSRF.
In the near future, SameSite cookies will allow you to stop CSRF attacks with much less effort.
There are two main vulnerabilities that manifest themselves in applications that handle XML a lot:
XXE attacks, among other things , can be used as a launching pad for local / remote file injection exploits.
Early versions of Google Docs were vulnerable to XXE attacks, but they are little known outside of business applications that handle large amounts of XML.
The main thing you need to do to protect against XXE attacks:
libxml_disable_entity_loader(true);
XPath injection is very similar to SQL injection, only here we are talking about XML documents.
Fortunately, in the PHP ecosystem, there are rarely situations when user input is transmitted in an XPath query.
Unfortunately, this also means that the best available solution (for precompiled and parameterized XPath queries) is missing in the PHP ecosystem.
We recommend using white lists of allowed characters for any data related to XPath queries.
<?php declare(strict_types=1); class SafeXPathEscaper { /** * @param string $input * @return string */ public static function allowAlphaNumeric(string $input): string { return \preg_replace('#[^A-Za-z0-9]#', '', $input); } /** * @param string $input * @return string */ public static function allowNumeric(string $input): string { return \preg_replace('#[^0-9]#', '', $input); } } // Usage: $selected = $xml->xpath( "/user/username/" . SafeXPathEscaper::allowAlphaNumeric( $_GET['username'] ) );
White lists are safer than black ones.
Read more: Secure (de) serialization in PHP
If you pass untrusted data to unserialize()
, then you are asking for two scenarios:
Many developers prefer to use JSON serialization instead, which is a noticeable improvement in software security. But keep in mind that json_decode()
is vulnerable to DDoS attacks through hash collisions . Unfortunately, a complete solution to the hash DOS problem in PHP has yet to be found .
Migrating from djb33 to Siphash with assignment 1 as the high-order bit for the hash of the string input value, 0 for the integer and with the key requested in advance, will provide full protection against these attacks, it will be provided by CSPRNG.
Unfortunately, the creators of PHP are not willing to partially sacrifice the performance they achieved in PHP 7, so it’s hard to convince them to abandon djb33 (very fast, but unsafe) in favor of SipHash (also fast, though not like djb33, but much safer) . A significant performance degradation may even interfere with the development of future versions, which will not benefit security.
Therefore, it is better to do this:
unserialize()
.sodium_crypto_auth()
and sodium_crypto_auth_verify()
with a secret key known only to the server.sodium_crypto_sign()
, and then check with sodium_crypto_sign_open()
and a third-party public key.Read more: How to safely store user passwords in 2016
Safe password storage used to be a topic of active discussion, but today it is easy to implement, especially in PHP:
$hash = \password_hash($password, PASSWORD_DEFAULT); if (\password_verify($password, $hash)) { // Authenticated. if (\password_needs_rehash($hash, PASSWORD_DEFAULT)) { // Rehash, update database. } }
You do not even need to know what the algorithm is, because if you use the latest version of PHP, you will use the latest technologies, and the user passwords will be automatically updated as soon as a new algorithm is available by default.
Whatever you do, do not do it like WordPress .
If interested: from PHP 5.5 to 7.2, the default algorithm is bcrypt. In the future, it may be replaced by Argon2, the winner of the Password Hashing Contest .
If you have not used the password_*
API before and you need to migrate legacy hashes, then do it that way . Many companies, such as Yahoo , have done wrong. It seems that Apple has recently caused an incorrect implementation of the Legacy hashes update to cause a bug with iamroot
.
We wrote a lot on this topic:
Sodium (libsodium). PHP 7.2 ( 5.2.4), sodium_compat , 7.2.
- . , .
, 2018- PHP-. .
: Building Searchable Encrypted Databases with PHP and SQL
, , . , . In particular:
, .
: -:
( ): , SELECT ?
:
, -.
SAPIENT , S ecure API EN gineering T oolkit, . Sapient / (shared) HTTPS.
Ed25519 API- , , « » / .
HTTP- , , (, Oauth). , - , , .
Sapient Sodium.
:
Paragon Initiative Enterprises Sapient ( open source ) Sapient.
Chronicle — , . - , , , «».
, Chronicle SIEM, , .
Chronicle (cross-sign) Chronicle / , Chronicle, .
Chronicle , .
Chronicle API, Sapient , — Quill .
, ( open source ), .
.
2015- PHP.
, ( PHP PHP 7.2), , . , .
, , , , , , , . , , ( Scott Helme ) . , .
Of course, this is not an exhaustive guide. , . — , . , PHP-.
, (PCI-DSS, ISO 27001 . .), . , .
— PHP- .
Source: https://habr.com/ru/post/344696/