Stop turning off CURLOPT_SSL_VERIFYPEER and fix your PHP config

As Pádraic Brady points out in a recent article about PHP security, there’s a whole lot of misinformation about how to deal with the error “SSL certificate problem, verify that the CA cert is OK” from curl. Nearly everyone advises that you turn CURLOPT_SSL_VERIFYPEER off (in fact, countless comments on the PHP manual page for curl_setopt tell you this). This is bad, because it allows your nice, encrypted stream of confidential data to be silently highjacked by a bad guy. Don’t do that! Instead, just fix your PHP installation so that it doesn’t get that error.

The error is caused by not having an up-to-date bundle of CA root certificates. This is typically a text file with a bunch of cryptographic signatures that curl uses to verify a host’s SSL certificate. You need to make sure that your installation of PHP has one of these files, and that it’s up to date.

Anyone running a recent Linux distribution is probably already OK, because they get the curl libraries bundled in through their package managers and recent curl libraries come with the latest CA root certificate bundle from Mozilla.org. This means you can just turn CURLOPT_SSL_VERIFYPEER on and you won’t get any errors.

For a PHP installation that doesn’t come with this file, like the Windows PHP distribution, you need to download the CA root certificate bundle and tell PHP where to find it. Luckily this is really easy. The curl website has the latest CA root certificate bundle ready to go, just download the .pem and save it where your PHP installation can access it.

Then you just need to edit your php.ini file to tell curl where you saved the .pem file. On my Windows test VM, I have several PHP versions under c:\php, so I put the file into that folder and added this line to each php.ini file:

curl.cainfo=c:\php\cacert.pem

After restarting the web service, curl now has a valid CA root certificate bundle and it can verify the SSL certificates of remote servers just fine. If it does get an error, it’s because the certificate is invalid — and that’s what you want it to do.

Job is done, safely.

facebooktwittergoogle_plusredditpinterestlinkedinmailfacebooktwittergoogle_plusredditpinterestlinkedinmail
  • http://www.magicboxsolutions.com Eric Ochoa

    Dude you saved my life, LOL. I had no idea that the windows distribution of PHP didn’t come with the certs and after spending a few days narrowing down my searches I found this blog entry. Thanks for this! :)

    Eric

  • http://joshmountain.com Josh Mountain

    Thanks Ross, great post. I wasn’t aware you could set the value in PHP.INI, that makes it much easier to manage different certs on a per-domain bases on a cpanel/whm server.

    • http://snippets.webaware.com.au/ Ross McKay

      G’day Josh,

      Note that you can also explicitly set the path to the certificate bundle in the call to curl(), by setting the CURLOPT_CAINFO option. Thus, if you have a web application that needs to access servers with self-signed certificates, you can add the .pem file to your web application and tell curl() to use that one instead. This is especially useful if you have to mix it up between public servers and servers with self-signed certs.

      cheers,
      Ross

  • Eric Caron

    On Linux, the code to append to php.ini looks like

    curl.cainfo = "/etc/ssl/certs/ca-certificates.crt"

    Thanks for this great blog post! Far too many people turn off VERIFYPEER and I hope more sysadmins come across this blog and start doing it right!

  • Pingback: WordPress update failing because of missing SSL certificate – Franz Josef Kaiser

  • http://dima.rudeshko.net/ Dima

    Thank you man! You saved my life.

  • Alex Gusev

    Thanks a lot! It’s just I need!!!

  • Natsu

    Well, doesn’t helped for the problem with WP and Jetpack – error still occures:

    The Jetpack server was unable to communicate with your site https://XXX [IXR -32300: transport error: http_request_failed SSL certificate problem: unable to get local issuer certificate]

    Have replaced my URL wit XXX hope that this line is enough for this.
    Hope to get a little help why the error still occures.

    • http://snippets.webaware.com.au/ Ross McKay

      Your problem there is that Jetpack won’t accept self-signed or otherwise invalid certificates. see here for details. Maybe you can install a free SSL certificate from StartSSL.

      cheers,
      Ross

  • http://Shrp.org Allen

    Dude, this is awesome! I was hesitant to make a global server change as is suggested all over SO. Your solution worked flawlessly on a win 7 dev environment.

    Thanks!

  • Kenton Kenton

    Thank you for this. Two additional notes for WAMP users. I needed the path to be of the form
    curl.cainfo=”c:cacert.pem”

    for it to work.
    Secondly, you need to restart WAMP.