Za svoje dlhé roky praxe v programovaní som sa miliónkrát stretol s tým, že mal niekto problém sa CURLom pripojiť na server, ktorý beží cez HTTPS. Bohužiaľ i množstvo veľkých odborníkov siahne po tom najjednoduchšom riešení a tým je obísť zabezpečenie. Často i na fórach sa objavujú rôzne ospravedlnenia, prečo to tak spraviť.

Tento postup len otvára zraniteľnosť a bezpečnostnú dieru do systému. Pre toto jednanie nie je ospravedlnenie, je to čisto len lenivosť a ukazuje to na nekvalitného programátora.

Je vám nasledovný kód povedomý?

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

Veľmi častý návod ako obísť problémy s SSL zabezpečením pri volaní CURL požiadaviek. Je to celé zle!

Ako tento problém vyriešiť?

Na tejto stránke si stačí stiahnuť export certifikátov (súbor „cacert.pem”), ktorý je pravidelne exportovaný z Mozilly.
Je tam možnosť i automatizovaného sťahovania, takže je možné si držať certifikáty na serveri neustále aktuálne.

Potom už len stačí tento súbor s certifikátmi podsunúť CURLu a ejha, SSL začne fungovať! Spravíme to nasledovne:

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, __DIR__.DIRECTORY_SEPARATOR.'cacert.pem');

Aké jednoduché, však? Stačí mať jeden súbor a CURLu ho podsunúť. Naozaj neexistuje ospravedlnenie prečo väčšina programátorov SSL proste ignoruje.

Mám „cacert.pem”, ale nefunguje to!

Existujú samozrejme situácie, kedy toto stačiť nemusí. Weby môžu mať napríklad vlastné podpísané certifikáty. Jedným z týchto príkladov je napríklad Česká Pošta, ktorá využíva svoju certifikačnú autoritu PostSignum.

Pre Vinylio.cz som práve včera začal riešiť evidenciu zásielok a ich aktualizáciu stavu. Česká Pošta na toto poskytuje API, ktoré beží na adrese: https://b2c.cpost.cz/.

I tu je však jednoduché riešenie, stačí si na stránke certifikačnej autority daný certifikát stiahnuť. Konkrétne na stránke http://www.postsignum.cz/certifikaty_autorit.html sa nachádza PEM „kořenová certifikační autorita PostSignum Root QCA 2”.

Riešenie opäť jednoduché, stačí certifikát v súbore „postsignum_qca2_root.pem” dodať CURLu:

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, __DIR__.DIRECTORY_SEPARATOR.'postsignum_qca2_root.pem');

Možnosť získať certifikáty je i napríklad ich exportom z Firefoxu.

No ... ale čo SOAP a SSL?

Áno, i to je jeden z problémov. Napríklad Aukro.cz svoje WebAPI prevádzkuje taktiež cez HTTPS. Postup je veľmi podobný predošlým situáciam a potrebujeme „cacert.pem”.

Ako na to pre SOAP? Tam už tých návodov cez vyhľadávanie človek nájde pomenej, ale i pre SOAP je to tak jednoduché. Stačí podsunúť certifikát nasledovne:

$context = stream_context_create(array(
    'ssl' => array(
        'cafile' => __DIR__.DIRECTORY_SEPARATOR.'cacert.pem',
    )
));

$soapOptions = array(
    'stream_context' => $context
);
$soap = new SoapClient('https://webapi.aukro.cz/?wsdl', $soapOptions);

CURL z command line

Pri volaní CURLu z príkazového riadku alebo konzoly sa dá použiť identický postup:

curl --cacert cacert.pem https://...

Záver

Prečo tento článok vznikol? Práve cez tento víkend som sa stretol s viacerými situáciami kedy som potreboval volať vzdialené služby a pri všetkých natrafil na problémy s SSL. Samozrejme som to nechcel riešiť vypnutím SSL, ale tým správnym riešením. Tak som to spísal a určite to pomôže ďalším do budúcnosti.

Zverejnené 10.09.2017