SSL error with file_get_contents

Asked

Viewed 4,348 times

2

When I try to open a url through file_get_contents, I’m having trouble when the page is https. I’m not talking about external pages, but in some libraries where the application’s own images are opened by file_get_contents, if you have https, generates the following error:

Warning: file_get_contents(): SSL operation failed with code 1. 
OpenSSL Error messages: error:14090086:SSL

routines:ssl3_get_server_certificate:certificate verify failed in /caminho/public/test.php on line 4

Warning: file_get_contents():
Failed to enable crypto in /caminho/public/test.php on line 4

Warning: file_get_contents(http://meusite.com.br): 
failed to open stream: operation failed in /caminho/public/test.php on line 4

Of course, I know that it is possible to solve this using the stream_context_create, but I don’t want this solution. I use library in my application that uses the file_get_contents (the DOMPDF)` and it is absurd to think about editing the source code, since if I have to do an update in the library, I would have to do the "patch" all the time.

I would like to understand what causes this error. This problem has started since we migrated from the old hosting. Currently Amazon today and the configuration was made by us. We requested the certificate keys of each of the domains and configured.

I wonder if the error indicates some kind of error in the configuration of our SSL, because when I do a file_get_contents for the urls of Google, for example, everything works normally.

Another important point is that SSL works normally in the browser, but is only with file_get_contents.

It is possible to check in that url.

Note: Please do not answer anything regarding "disable" SSL verification on requests, as I do not want to create another problem (no "temporary definitive solutions"). I want to understand what’s happening and resolve.

  • While SSL for lack authentication is mandatory. You can different for Heroku has PHP

  • see if that answer and this php wiki help you.

  • PHP has a documentation for that reason.

  • Try Openssl (http://php.net/manual/en/book.openssl.php) or Nginx can help tb

2 answers

4

I thank my friend @Guilhermenascimento for his reply and @Bacco for helping in the chat to solve the problem.

I finally managed to solve!

Let’s take the necessary steps. I am using version 5.6 of PHP.

Once you have made all the necessary settings in apache, you need to make a configuration for PHP.

First, we need to find the location of the certificate file that PHP is reading. It can be seen through the function openssl_get_cert_locations.

In my case, she returned the following:

[
 "default_cert_file" => "/usr/lib/ssl/cert.pem",
 "default_cert_file_env" => "SSL_CERT_FILE",
 "default_cert_dir" => "/usr/lib/ssl/certs",
 "default_cert_dir_env" => "SSL_CERT_DIR",
 "default_private_dir" => "/usr/lib/ssl/private",
 "default_default_cert_area" => "/usr/lib/ssl",
 "ini_cafile" => "/usr/lib/ssl/cert.pem",
 "ini_capath" => "",
]

Noting the value of default_cert_file, you now know where PHP reads from cerificated intermediate.

Explaining in a very quick way the file cert.pem contains a list of trusted certificates from each Certification Authority. It is called CA Bundle.

You must lower it in this link and move it to the location returned in default_cert_file. Or else you can download it to another location and set, through the php.ini, the location of your archive via the openssl.cafile.

openssl.cafile = /caminho/do/cacert.pem

Every time you make a request via PHP via curl or any other function using the wrapper https, using the option verify_peer, PHP will read this file to know which are the valid Certification Authority.

After these operations, if still the error shown in the question remains, you must manually add, at the end of the file, the intermediate code of your SSL certificate.

The user @Bacco recommended me to access by the browser itself and download this code.

See the image:

Baixando o certificado

In my case, I chose the option Rapid SSL SHA256 CA and exported the data. You can do this in any browser. The name will change according to your Certification Authority.

Important

From the moment you are adding a new CA to your system, you’re saying you trust "blindly" that entity, so just do that if really if it is a certificate that you are sure of absolute origin and suitability.

Note: You can also find the code on the SSL service provider website, but in my case it worked better by downloading from the browser.

The code you will download from the certificate, will look something like this:

-----BEGIN CERTIFICATE-----
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv
YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh
bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT
aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln
bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6
ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp
s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN
S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL
TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C
ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i
YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN
BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu
01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7
9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
-----END CERTIFICATE-----

After that, edit the file marked as default_cert_file in your PHP. In my case, I renamed it to cert.pem after downloading. Now, add the certificate code you downloaded from the browser (or the CA certificate you’re using) and add it to the above mentioned file. It is recommended you put at the end of your.

After that you may need to restart Apache, but in my case, you didn’t need to.

Link to the CA Bundle:

https://curl.haxx.se/ca/cacert.pem

  • 1

    Important to mention that if you add a certificate from a dubious entity, you are breaking all the security of SSL. You have to be absolutely sure what you’re doing to add a new CA to a system.

  • @Bacco can add that to the answer. Really, I’m a denial in SSL :D

  • 1

    I made a scandalous addendum, format as you think you should :P

  • The addendum had to be scandalous, because it puts at risk users who would not know what they are doing,

2

I may be wrong, but according to the answers here https://stackoverflow.com/a/26151993/1518921 you must download the http://curl.haxx.se/ca/cacert.pem (although I’m sure that if you install SSL on your server there will already be this file) and set the stream like this:

$url = 'https://site';

$streamSSL = stream_context_create(array(
    "ssl"=>array(
        "cafile" => "/path/cacert.pem",
        "verify_peer"=> true,
        "verify_peer_name"=> true
    )
));

$response = file_get_contents($url, false, $streamSSL);

PHP 5.6

In php5.6 it is possible to configure openssl via php.ini (http://php.net/manual/en/openssl.configuration.php):

openssl.cafile "" PHP_INI_PERDIR Available since PHP 5.6.0

openssl.capath "" PHP_INI_PERDIR Available since PHP 5.6.0

Example:

openssl.cafile=/path/cacert.pem

So I believe it is possible to configure the path. About the capath if unspecified it will look for a suitable one, then I think it might be possible to use file_get_contents directly:

$url = 'https://site';

$response = file_get_contents($url, false);

CURL

As I mentioned, I believe that if SSL (openssl) is installed it should work without needing settings, Curl is also like this but it is available since the Available since PHP 5.3.7 in php.ini using curl.cainfo = /path/cacert.pem:

$url = 'https://site';

$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSLVERSION,3); 
$result = curl_exec($ch);
curl_close($ch);

Note: The path of the certificate must be absolute

Install ssl

I believe that the only thing that is necessary to configure is openssl enabling the extension for it, if it is Windows and distros based on debian (archive) just remove comment (;extension=) in the following line:

extension=openssl.so

or (windows):

extension=php_openssl.dll

However if you compiled PHP yourself (using make for example, it will be necessary to recompile) using the parameter --with-openssl[=DIR] (http://php.net/manual/en/openssl.installation.php)

Being Debian/Ubuntu/etc install libssl (if not installed):

  • Debian:

    su
    apt-get install libssl1.0.0
    
  • Ubuntu:

    sudo apt-get install libssl1.0.0
    
  • The only part that’s bad in your answer is that I would have to define in file_get_contents. The library is the one who does the query, so it’s impossible to change it. Could you do it for PHP.INI? (I’m racking my brain here)

  • @Wallacemaxters do not know inform, but I understood your need you must be using a ready library, usually when we have openssl installed I think that by CURL works without needing much configuration, I will edit the answer, I think you should have yes by php.ini

  • I need to understand what happens, when I do by my local application, the same error occurs.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.