PHP: cURL over HTTPS and CURLOPT_SSL_VERIFYPEER

I have a couple of sites that I control.   I need to post data from site one to site two.   I don't need a response from site two, just post a couple of variables and stay on site one.   If I use https, I found I can use CURLOPT_SSL_VERIFYPEER set to false to allow the https connection.  

I assume this should be safe since I control both sites.  What needs to be added to use CURLOPT_SSL_VERIFYPEER set to true/default?
 
$url = 'https://my_other_site.com/test.php';
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);

 curl_setopt($ch, CURLOPT_POSTFIELDS,
          http_build_query(
              array(
                  'var1' => urlencode('abc123'),
                  'var2 => urlencode('xyz456')
              )
          )
 );

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

$response = curl_exec ($ch);


if($response) 
{
	echo  $response;
}
else
{
	echo curl_error($ch);
}
    
curl_close ($ch);

Open in new window

LVL 55
Scott Fell, EE MVEDeveloper & EE ModeratorAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

GaryCommented:
Set it to to true
Also need if the path is different from the curl default.
curl_setopt ($ch, CURLOPT_CAINFO, "/pathto/cacert.pem");

If you don't have an up to date ca cert bundle then get it from
http://curl.haxx.se/

p.s.
curl doesn't come with a CA bundle by default anymore, so it's likely you don't have them.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Radek BaranowskiFull-stack Java DeveloperCommented:
In other words you need to obtain public key of site two certificate and place it on a trust store on site one for it to be able to verify if ssl connection from site two uses known and valid certificate.
0
Scott Fell, EE MVEDeveloper & EE ModeratorAuthor Commented:
The path to cert from site one?
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

Radek BaranowskiFull-stack Java DeveloperCommented:
If site one had ssl up and running the best way to obtain is public key is to open its https port in browser,save the certificate and add it to trust store on site two. You might need to use opensll tools to convert it to pem format of That's what curl needs.
0
Radek BaranowskiFull-stack Java DeveloperCommented:
*openssl
0
GaryCommented:
No the path to the certs on site one - it needs to be able to negotiate what site 2 is sending.
Since curl doesn't come with any CA certs then it doesn't negotiate a verifiable secure connection (verify peer set to false will accept any ssl certificate).
0
GaryCommented:
Does site 2 have a real ssl cert and not a self generated one? If it's self generated then you may as well just use false, as true would never work anyway
0
Scott Fell, EE MVEDeveloper & EE ModeratorAuthor Commented:
I have real certs on both sites
0
Ray PaseurCommented:
You can use cURL POST for this and you can also use fSockOpen() to make a post-method request.  A safe design for this handshake process, used by PayPal, goes something like this:

1. Site A prepares the post data and saves the post arguments in the database
2. Site A makes a post to Site B.
3. Site B makes a post back to Site A with "cmd=>verify" in the first request element, with the other request elements appended in order so that Site A can verify the data.
4. Site A looks up the post arguments in the database and if they match, makes a post back to Site B with the word "verified" and if they don't match, responds with "wrong."

If you already have the HTTPS connection, why would you be concerned about using the certificates?
0
Scott Fell, EE MVEDeveloper & EE ModeratorAuthor Commented:
I looked at my authorize.net sdk.  They have a file named cert.pem and the code that access it is
 if ($this->VERIFY_PEER) {
            curl_setopt($curl_request, CURLOPT_CAINFO, dirname(dirname(__FILE__)) . '/ssl/cert.pem');
        } else {
			if ($this->_log_file) {
				file_put_contents($this->_log_file, "----Request----\nInvalid SSL option\n", FILE_APPEND);
			}
			return false;
        }

Open in new window


Would I just make a pem file of one of my certificates?
0
GaryCommented:
So just use the full path to the ssl/cert.pem file for the CAINFO path
0
GaryCommented:
Not sure if you mean that is already on your server...grab them here.
http://curl.haxx.se/docs/caextract.html
0
Scott Fell, EE MVEDeveloper & EE ModeratorAuthor Commented:
That worked.    I downloaded http://curl.haxx.se/ca/cacert.pem and saved to my server and then used CURLOPT_CAINFO as below (windows) and worked.  

curl_setopt ($ch, CURLOPT_CAINFO, '\inetpub\vhosts\MySite\httpdocs\folder\cacert.pem');
0
gr8gonzoConsultantCommented:
Sounds like you're already getting help with the "how" but allow me to respond to: "I assume this should be safe since I control both sites. "

That is a bad assumption. By verifying the remote certificate, you are helping avoid man-in-the-middle attacks. Basically, a malicious user can blast some specially-crafted network packets to your servers, telling your servers that they should route traffic through a different gateway. At this point, the malicious user could route traffic INTENDED for your "Site B" to his/her own server and grab the data. Of course, it's useless to them to grab encrypted data, so part of that process is to use THEIR own SSL certificate instead, so that your "Site A" is encrypting data using the malicious user's SSL public certificate (which identifies itself as "Site B"). Now, when the malicious user's server gets traffic that goes to Site B, it can decrypt the traffic and get to the real data. Optionally, it can then pass on the original request to Site B and return Site B's response back to Site A. This way, it SEEMS like everything is working fine. However, you'll have no idea that there is a server in-between Site A and Site B that is capturing all the original data and responses.

So when you tell cURL to verify the certificate of Site B, it is checking the entire certificate chain (the certificate itself and also the certificates that issued it) to make sure you're actually dealing with the Site B certificate and not some other 3rd party certificate that you're not expecting. And unless the malicious user has access to Site B's private key, they cannot use Site B's certificate to disguise themselves.

Hopefully all of that makes sense and explains why you should always verify peer certificates (even if both sites are 100% trustworthy). :)
0
Scott Fell, EE MVEDeveloper & EE ModeratorAuthor Commented:
Thanks gr8gonzo, great point.  I just read that and that's why I didn't stick with setting CURLOPT_SSL_VERIFYPEER to false.  

Below is what I ended up with where cacert.pem is from http://curl.haxx.se/ca/cacert.pem 

$url = 'https://my_other_site.com/test.php';
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST, 1);

 curl_setopt($ch, CURLOPT_POSTFIELDS,
          http_build_query(
              array(
                  'var1' => urlencode('abc123'),
                  'var2 => urlencode('xyz456')
              )
          )
 );

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // changed to true
curl_setopt ($ch, CURLOPT_CAINFO, '\inetpub\vhosts\MySite\httpdocs\folder\cacert.pem');  //added

$response = curl_exec ($ch);


if($response) 
{
	echo  $response;
}
else
{
	echo curl_error($ch);
}
    
curl_close ($ch);

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.