📜 ⬆️ ⬇️

The book Security in PHP (part 4). The lack of security at the transport level (HTTPS, TLS and SSL)


The book "Security in PHP" (part 1)
The book "Security in PHP" (part 2)
The book "Security in PHP" (part 3)


Communication over the Internet between participants in the process carries risks. When you send a payment order to the store using an online service, you definitely do not want an attacker to intercept, read, change or re-repeat the HTTP request to the online application. Just imagine the consequences of what the attacker considers the cookie of your session or will change the payee, product, billing address. Or embed in markup sent by the store in response to a user request, your HTML or JavaScript.


Protecting sensitive and personal data is a serious business. Browser and application users have extremely high expectations regarding security. Of particular importance are the integrity of transactions with bank cards, privacy and identification information. Solving these problems when it comes to protecting the data transfer between two participants in the process requires security at the transport level, which usually includes HTTPS, TLS and SSL.


The main objectives of protection measures:



The most important point: for successful protection at the transport level, it is necessary to solve all four tasks. If at least we do not succeed in something, then serious problems await us.


Many people mistakenly believe that encryption is a key task, and all others are optional. This is completely wrong. When encrypting the transmitted data, the recipient must be able to decrypt them. This is possible when the client and server agree on an encryption key (among other things) during the negotiation phase when the client attempts to establish a secure connection. However, an attacker is able to penetrate between the client and the server using simple methods. It can force the client machine to consider it a server, this is called a man-in-the-middle attack (MitM, Man-in-the-Middle). And then the negotiations on the encryption key will be conducted not with the real server, but with a fake one. This will allow the attacker to decrypt all the data sent by the client. Obviously, to protect against this scenario, we need to meet the second requirement: the ability to verify the identity of the server with which the client communicates. Without this check, we will not distinguish the target server from the dummy.


So for safe communication, you must comply with all four conditions. Each of them perfectly complements the other three, and only together they provide reliable and sustainable security at the transport level (Transport Layer Security (TLS)).


In addition to the technical aspects of TLS, there is another side to quality security. For example, if we allow the user to enter HTTP data into the application authorization form, then we must accept the possibility of a MitM attack, during which authorization data will be intercepted and later used. Or if we allow pages that load over HTTPS to load non-HTTPS resources, we must accept that the MitM attacker has a transport with which it can conduct cross-site scripting attacks and turn the user’s browser into a pre-programmed weapon capable of act transparently through a browser-based HTTPS connection.


The obvious criteria based on the four main tasks described above will help us assess the quality of any security measures:



These are key questions for the entire fourth part of the book. We will go into some particular details, but everything will somehow revolve around these questions and defining vulnerabilities, when we cannot give affirmative answers.


Another important point is what data should be protected. Obviously, these are details of bank cards, personal identification information, and passwords. What about the user session ID? If we protect passwords, but not IDs, then an attacker can still steal transmitted cookies and perform a session hijacking attack, impersonating the user on his own computer. Protecting authorization forms alone is NEVER enough to preserve authorization data. The best protection is achieved if the user session is performed only within HTTPS from the moment data is entered into the form until the end of the session.


Now you need to understand why the word "not enough" appeared. The problem of implementing SSL / TLS is not only in their non-use, but also in the use of inadequate for maximum security measure.


We will consider the lack of security at the transport level from three points of view:



The first point is to confirm that our web application is safely connected to other participants in the process. TLS is typically used for web services APIs and many other input sources necessary for the operation of the application.


The second point is the interaction of users with a web application via browsers or other client applications. In this case, we reveal a secure URL, and we need to make sure that security measures are implemented correctly so that there is no risk of circumventing them.


The third point is all sorts of fancy solutions (curious oddity). Since SSL / TLS have a reputation for incorrectly implemented standards by programmers, there are many ways to ensure a secure connection without their participation. As an example, the use of signed requests by the OAuth protocol, which do not require SSL / TLS, but offer a number of security measures provided by those (in particular, the encryption of the request data is omitted). So this is not an ideal solution, but it is still better than an incorrectly configured SSL / TLS library.


Before we get into the details, let's first look at TLS as a whole and get some basic knowledge, and then dive into the guts of PHP.


Definitions and baseline vulnerabilities


TLS is a generic name that describes measures to create a secure connection between two participants using encryption, identity verification, etc. Most of you are already familiar with three abbreviations: HTTPS, SSL, TLS. Let's take a quick look at them and their relationships.


SSL / TLS from PHP (server-to-server)


No matter how much I love PHP as a programming language, even the most cursory overview of popular open source libraries makes it clear: they have security vulnerabilities at every step. And the PHP community tolerates these vulnerabilities for no good reason only because it is easier to put users at risk than to solve problems. The situation is aggravated by the fact that PHP itself suffers from a very bad implementation of SSL / TLS in PHP streams used everywhere - from HTTP clients based on sockets to file_get_contents() and other functions of the file system. Add to this the fact that the authors of PHP libraries do not even try to discuss the possible security implications of SSL / TLS failures.


If you do not do anything described in this chapter, then at least perform all HTTPS requests using the cURL extension for PHP. Its default configuration provides security, and the extension relies on the expert judgment of a large number of users outside the PHP domain. So take this simple step to improve security and you will not regret it. The ideal solution would be if the PHP authors finally wake up and implement the Secure By Default principle in the built-in support for SSL / TLS.


My introduction to SSL / TLS in PHP was very rude. TLS vulnerabilities are much simpler than most security problems, and we all know how important this is for browsers. But our server application is an equally important link in the security chain of user data. So let's take a closer look at SSL / TLS in PHP, in turn, looking at PHP streams and the excellent cURL extension.


PHP streams


For those who are not familiar with streams: they are needed to generalize (generalize) files, networks, and other operations that share common functionality. In order for a stream to know how to work with a specific protocol, “wrappers” are used to allow the stream to represent a file, an HTTP request, a PHAR archive, data URIs (RFC 2397), etc. file function) with the corresponding URL, which denote the wrapper and the target resource.


 file_get_contents('file:///tmp/file.ext'); 

By default, threads use a file wrapper (File Wrapper), so usually you don’t need a URL, even a relative path to the files is sufficient. This is obvious because most file system functions like file() , include() , require_once and file_get_contents() accept stream references. So rewrite the previous example:


 file_get_contents('/tmp/file.ext'); 

Given the topic under discussion, you can do this:


 file_get_contents('http://www.example.com'); 

Since file system functions — for example, file_get_contents() — support HTTP wrapped streams (HTTP wrapped streams), they form an HTTP client in PHP that is very easy to access. You can use them if you do not feel the need to use dedicated libraries to create HTTP clients like Guzzle, Buzz, or classes from the Zend \Zend\Http\Client framework. In order for your simple client to work, you need to enable the allow_url_fopen option in the php.ini . By default, it is enabled.


Of course, the inclusion of allow_url_fopen entails the risk of attacks with remote execution of files, bypassing access control or information disclosure. If an attacker can, at his choice, inject a remote URI into the file function, he will easily force the application to execute, store or display the downloaded file, including from a remote unreliable source.


Do not forget that the files will be uploaded from localhost , which means they will be able to bypass access control based on restrictions imposed on the local server. And if the option allow_url_fopen enabled by default, then for the greatest security it will have to be disabled.


Let's get back to using PHP streams as a simple HTTP client (and now you know that this is not recommended ). Everything becomes more interesting if you try to do this:


 $url = 'https://api.twitter.com/1/statuses/public_timeline.json'; $result = file_get_contents($url); 

This is a simple unauthenticated request via HTTPS to (former) Twitter API 1.0. There is a serious leak. For requests performed using HTTPS- (https: //) and FTPS- (ftps: //) wrappers, PHP uses the SSL Context . There are many settings for SSL / TLS, as well as their default values, which are completely unsafe. We will rewrite the example to illustrate how you can insert the original set of SSL Context as a parameter in the file_get_contents() :


 $url = 'https://api.twitter.com/1/statuses/public_timeline.json'; $contextOptions = array( 'ssl' => array() ); $sslContext = stream_context_create($contextOptions); $result = file_get_contents($url, NULL, $sslContext); 

As mentioned above, if you incorrectly configure SSL / TLS, then the application will be defenseless against man-in-the-middle attacks. PHP streams by default are completely insecure when working over SSL / TLS. So let's fix our example so that it becomes completely safe.


 $url = 'https://api.twitter.com/1/statuses/public_timeline.json'; $contextOptions = array( 'ssl' => array( 'verify_peer' => true, 'cafile' => '/etc/ssl/certs/ca-certificates.crt', 'verify_depth' => 5, 'CN_match' => 'api.twitter.com', 'disable_compression' => true, 'SNI_enabled' => true, 'ciphers' => 'ALL!EXPORT!EXPORT40!EXPORT56!aNULL!LOW!RC4' ) ); $sslContext = stream_context_create($contextOptions); $result = file_get_contents($url, NULL, $sslContext); 

Now everything is all right! If you compare with the previous version, you will notice that we configured four options that were not originally configured or disabled by PHP. Let's see what they do.



Peer Verification — validates the SSL certificate provided by the host to which we sent the HTTPS request. The correct certificate is signed with the private key of a trusted Certificate Authority (CA). The verification can be performed using the CA public key, which is included in the file set as a cafile option for the SSL Context used by us. In addition, the certificate should not be expired.



The cafile should point to a valid file containing the public key of the trusted CA. In PHP, this is not done automatically, so keep the keys in a related file in a special format (usually PEM or CRT). If you can not find a copy, then download and spars from Mozilla VCS . Without this file, it is impossible to check the peer, and the request will not be executed.



This setting specifies the maximum number of intermediate certificate issuers, that is, the number of CA certificates that can be used when verifying the original client certificate.



The three previous options relate to verifying the certificate provided by the server. However, they do not help us understand whether the domain name or IP requested by us is valid, that is, the part of the URL associated with the host. To find out if the certificate is bound to the current domain / IP, let's perform a host verification (Host Verification). In PHP, you need to set the CN_match host value (in the SSL Context), including the subdomain, if any. While this option is set, PHP will perform an internal check. If you do not do this, then during the man-in-the-middle attack, an attacker can provide a valid certificate signed by a trusted CA. But the certificate will be valid for the domain under the control of the attacker, and not for the domain to which you want to connect. Configuring the CN_match option will help identify the mismatch of certificates and will result in a non- CN_match HTTPS request.


Since a valid certificate used by an attacker will contain the attacker's identification information (this is the condition for receiving it!), Keep in mind that a savvy attacker has access to any number of valid, CA-signed certificates, complete with corresponding private keys. They could have been stolen from other companies or slipped through checking reliable CAs. This happened in 2011 when DigiNotor issued a certificate for an unknown party to google.com . She used him to attack "man in the middle", mainly against Iranian users.



This option appeared in PHP 5.4.13. It is needed to protect against CRIME and other attacks with the addition of blocks like BEAST. At the time of this writing, the option has been available for 10 months. It took a lot of patience to find almost the only example of its use in open source PHP.



Includes support for specifying the server name (Server Name Indication) when any single IP can be configured to operate multiple SSL certificates, so as not to be limited to one certificate for all sites or non-HTTP services hosted on this IP.



This setting helps to show which ciphers should or should not be chosen when establishing SSL / TLS connections. The default list is provided by the openssl extension. It contains insecure ciphers that should be disabled unless you are forced to use them. The following list, using the openssl syntax, was implemented by cURL in January 2014. The alternative list offered by Mozilla may be better, because it focuses on perfect forwarding security (Perfect Forward Secrecy), this is the best practical approach. Mozilla longer list:


 ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK 

Restrictions


As described above, checking the certificate provided by the server for validity for the host specified in the URL you are using during the man-in-the-middle attack does not allow you to simply slip any valid certificate purchased or received illegally. This is one of the four essential steps to make your connection completely secure.


The system performs the validation due to the CN_match parameter, declared by the SSL Context in the PHP HTTPS wrapper. But he has a flaw. At the time of writing the book, only the common name (Common Name, CN) of the SSL certificate was checked, and the validity of the Subject Alternative Name, SAN field defined by the certificate was not checked. SAN allows you to protect multiple domain names with a single SSL certificate, so it is extremely important and supported by all modern browsers. And since PHP does not yet support SAN verification, SSL / TLS connections to a domain protected by such a certificate will not be installed. SAN support will appear in PHP from version 5.6.


On the other hand, the out-of-box cURL extension supports SAN, so its use is much more reliable and preferable compared to PHP-embedded HTTPS / FTPS wrappers. In this regard, the use of PHP streams is likely to lead to erroneous behavior, and impatient programmers simply disable the check on the host as a whole, which is highly undesirable to do.


SSL Context in PHP Sockets


Many HTTP clients in PHP offer both a cURL adapter and the default PHP socket adapter. Using the latter by default means that cURL is an optional extension, in practice it can be disabled.


PHP sockets use the same SSL Context resource as PHP streams, so there are the same problems and limitations as described above. A side effect: many major HTTP clients are likely to be a priori unreliable and less secure than they should be. Such client libraries, when possible, need to be configured so that they use a cURL adapter. Also, make sure that customers do not forget to use the right approach to SSL / TLS security.


Additional risks


CURL extension


Unlike PHP streams, the cURL extension only transfers data, including HTTP requests. Also, unlike SSL Context streams, cURL by default safely performs requests via SSL / TLS. You do not need to do anything for this, unless it was compiled without the CA certificates package repository (for example, without the cert.pem file or the ca-bundle.crt file with certificates of trusted CAs).


Since this does not require a special approach, you can call the Twitter API - in the same way as we did before for SSL / TLS using a PHP stream. A minimum of hassle, and do not worry about the fact that you forget about some options that will open you to attack the "man in the middle."


 $url = 'https://api.twitter.com/1/statuses/public_timeline.json'; $req = curl_init($url); curl_setopt($req, CURLOPT_RETURNTRANSFER, TRUE); $result = curl_exec($req); 

Therefore, for HTTPS requests, I recommend cURL. By default, this is safe, and PHP streams are most certainly not. Otherwise, just use cURL, it will save you from a headache. Ultimately, cURL is safer, requires less code, and less likely to fail SSL / TLS security errors due to human error.


At the time of this writing, PHP 5.6 has reached alpha1. In the final release, more secure defaults will appear for PHP streams and socket connections over SSL / TLS. These innovations will not be ported to PHP 5.3, 5.4 or 5.5. Therefore, programmers will have to consciously implement secure default settings until PHP 5.6 is turned into the required minimum.


Of course, if the cURL extension was enabled without configuring the placement of a package of trusted certificates, then the above example will not work. For publicly distributed libraries, you need to force safe behavior:


 $url = 'https://api.twitter.com/1/statuses/public_timeline.json'; $req = curl_init($url); curl_setopt($req, CURLOPT_RETURNTRANSFER, TRUE); $result = curl_exec($req); /** * ,     SSL,      * CA-, ,      *  ext/curl.  77   CURLE_SSL_CACERT_BADFILE,  *  -         PHP. */ $error = curl_errno($req); if ($error == CURLE_SSL_PEER_CERTIFICATE || $error == CURLE_SSL_CACERT || $error == 77) { curl_setopt($req, CURLOPT_CAINFO, __DIR__ . '/cert-bundle.crt'); $result = curl_exec($req); } /** *        . *     SSL    ;). */ 

The most difficult part is obviously distributing the file with the certificate package cert-bundle.crt or cafile.pem (the file name varies depending on the source!). The certificate of any CA can be revoked at any time by most browsers in the event of a breach of their security or peer review processes, so not updating the certificate file for a long time is not a good idea. However, the most obvious solution is to distribute a copy of the file with the library or application for which it is required.


If you cannot strictly control the renewal of the distributed certificate package, or you need a tool that can periodically perform this verification for you, use Sslurp .


Client-side SSL / TLS connections (client / browser-server)


Most of what we talked about before was related to SSL / TLS connections established with another server initiated by PHP web applications. Of course, there are still a number of security issues when an application provides SSL / TLS support to client browsers and other applications. Here there is a risk of attacks related to transport vulnerabilities.


If you think about it, then all this is quite simple. Let's say I create an online application that provides protection while entering a user password. The authorization form is served via HTTPS, and data from it is also transmitted via HTTPS. Mission Complete. To get started in your account, the user has been redirected to an HTTP URL. Notice the problem?


When there is a threat of a “man in the middle” attack, we should not just protect the authorization form, and then close it. Cookies of user sessions and all input data, as well as all user-generated HTML code will not be safe when working via HTTP. An attacker can steal cookies and impersonate a user, can embed XSS-code in the pages received by users to perform tasks on behalf of users or control their actions. And for all this, no user passwords are needed.


Protecting the authentication process using HTTPS alone will prevent direct password theft, but will not protect against session hijacking, other forms of data theft, or the introduction of code for XSS attacks. By protecting only one user with HTTPS, we provide insufficient protection at the transport level. Our users remain vulnerable to man-in-the-middle attacks.


')

Source: https://habr.com/ru/post/352444/


All Articles