LINUX.ORG.RU

Curl: SSL read errno 104 на Cloudflare Origin Certificate

 , ,


0

2

Доброго времени суток!

Есть сервис (API с ограниченным доступом), IP адрес защищен Cloudflare. Мне известен реальный IP адрес сервера и для предотвращения разных проблем (Cloudflare имеет привычку блокировать автоматические запросы когда не нужно) я обращаюсь к реальному IP напрямую (прописал в /etc/hosts).

В браузере все открывается нормально (пропустить ошибку проверки сертификата и сайт открылся). Скрипт на PHP начал выдавать какую-то ерунду.

SSL read: error:00000000:lib(0):func(0):reason(0), errno 104

Универсальное решение всех проблем с сертификатами при подобных манипуляциях

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

не дает ожидаемого результата. Ранее на сервере стоял сертификат Let’s Encrypt (валидный) и IP адрес иногда менялся на Cloudflare, иногда защита была отключена. Сейчас сертификат хоста Cloudflare Origin Certificate подписанный Cloudflare Origin SSL Certificate Authority - разница только в этом. Wget на той же машине успешно загружает robots.txt с IP адреса, прописанного в hosts (с –no-check-certificate, естественно). Проверялось с 2 разных машин, т.о. дело не в локальных настройках.

Как заставить cURL это съесть?

И небольшое уточнение. Проблема возникает только при использовании cURL на PHP, т.к. команда вида

curl --http1.1 -vvv --insecure "https://hostname/api/" -d 'param1=val1&param2={json:true}'

отрабатывает относительно успешно (ответ API не все параметры указаны, есть какие-то проблемы с парсингом json, переданным из консоли). PHP скрипт заведомо рабочий, несколько лет уже используется. Сейчас в него добавлен вывод HTTP заголовков.



Последнее исправление: Dima_228 (всего исправлений: 2)

Ответ на: комментарий от etwrq

Ну с одной стороны обновил (ничего)

Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.

с другой стороны, это глобальное для системы и если бы проблема была тут - ни wget, ни консольный curl не подключались бы. Да и CURLOPT_SSL_VERIFYPEER / CURLOPT_SSL_VERIFYHOST выключено, это всегда решало все проблемы.

Dima_228
() автор топика
Ответ на: комментарий от etwrq

Идея классная, спасибо, никогда не использовал CURLOPT_VERBOSE в PHP. А вот результат:

php test.php
*   Trying [ip address]...
* TCP_NODELAY set
* Connected to *** ([ip address]) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: O=CloudFlare, Inc.; OU=CloudFlare Origin CA; CN=CloudFlare Origin Certificate
*  start date: May ** 16:07:00 2022 GMT
*  expire date: May ** 16:07:00 2037 GMT
*  issuer: C=US; O=CloudFlare, Inc.; OU=CloudFlare Origin SSL Certificate Authority; L=San Francisco; ST=California
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
> GET /robots.txt HTTP/1.1
Host: ****
Accept: */*

* SSL read: error:00000000:lib(0):func(0):reason(0), errno 104
* Curl_http_done: called premature == 1
* stopped the pause stream!
* Closing connection 0
[Err]: SSL read: error:00000000:lib(0):func(0):reason(0), errno 104
OUT LENGTH 0

Curl в PHP использует то что написано в /etc/hosts, вижу по сертификату. Curl в командной строке почему-то ломился на IP адрес CloudFlare, пришлось ему еще –resolve добавить. При этом на PHP - ошибка и пустой ответ, консольный curl выдает содержимое robots.txt

Dima_228
() автор топика
Ответ на: комментарий от Dima_228

а какие версии php curl libcurl слоя ssl на котором всё это завязано?
попробуй с последними версиями собрать контейнер или виртуалку арча, например т.к. роллинг и там всё свежее, и запустить скрипт из него, что бы исключить проблему старых версий и багов софта.
ну и еще:
https://github.com/curl/curl/issues/4409 тут обсуждение этого бага.
https://drjohnstechtalk.com/blog/2017/05/curl-showing-its-age-with-ssl-error/ тут несколько кейсов, в т.ч. и по твоему багу.
ещё вариант, если нету возможности обновить на хосте софт - можно, я думаю, скачать исходники(srpm например) и посмотреть какие флаги в консольном курле прописаны для опции --insecure такие же попробовать в скрипте прописать.

etwrq ★★★★★
()
Последнее исправление: etwrq (всего исправлений: 2)
Ответ на: комментарий от caoutchouckcha

Интересно чукчи пляшут… Попробовал еще исходя из написанного в одном длинном тексте разные версии TLS (CURLOPT_SSLVERSION = 4,5,6) результат - один фиг 104 ошибка. phpinfo заявляет что cURL 7.52.1, OpenSSL/1.0.2u, консольный curl показывает ту же версию 7.52.1 Следующее извращение

printf 'GET /robots.txt HTTP/1.1\r\nHost: mydomain.com\r\nConnection: close\r\n\r\n' | openssl s_client -quiet -connect ipaddress:443

выдало

depth=0 O = "CloudFlare, Inc.", OU = CloudFlare Origin CA, CN = CloudFlare Origin Certificate
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 O = "CloudFlare, Inc.", OU = CloudFlare Origin CA, CN = CloudFlare Origin Certificate
verify error:num=21:unable to verify the first certificate
verify return:1
read:errno=104

То есть понятно что есть проблемы с доверием к этому сертификату, но мне не понятно 104я ошибка связана с предыдущими или она идет отдельно.

Добавил в строку openssl -state -nbio

SSL_connect:before SSL initialization
SSL_connect:SSLv3/TLS write client hello
SSL_connect:error in SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS write client hello
SSL_connect:SSLv3/TLS read server hello
depth=0 O = "CloudFlare, Inc.", OU = CloudFlare Origin CA, CN = CloudFlare Origin Certificate
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 O = "CloudFlare, Inc.", OU = CloudFlare Origin CA, CN = CloudFlare Origin Certificate
verify error:num=21:unable to verify the first certificate
verify return:1
SSL_connect:SSLv3/TLS read server certificate
SSL_connect:SSLv3/TLS read server key exchange
SSL_connect:SSLv3/TLS read server done
SSL_connect:SSLv3/TLS write client key exchange
SSL_connect:SSLv3/TLS write change cipher spec
SSL_connect:SSLv3/TLS write finished
SSL_connect:error in SSLv3/TLS write finished
SSL_connect:SSLv3/TLS write finished
SSL_connect:SSLv3/TLS read server session ticket
SSL_connect:SSLv3/TLS read change cipher spec
SSL_connect:SSLv3/TLS read finished
read:errno=104

вот что выдало, то есть якобы с TLS/SSL все нормально. С CURLOPT_CUSTOMREQUEST попробовал, все то же.

GET /robots.txt HTTP/1.0
Host: mydomain.com
Accept: */*

Запрос полностью валидный

Через Cloudflare ответ HTTP/1.1 520 мне точно не подходит потому и приходится ломиться по прямому IP адресу. После всего оказалось что его попускает если указать User-Agent в запросе (хотя в этом коде, использующем API не первый год, его никогда не было.

В общем решил пока не воевать с origin, если CloudFlare не станет спонтанно блокировать запросы то можно будет работать через него.

Dima_228
() автор топика
Ответ на: комментарий от Dima_228

Мне показалось, или ты не со своего хоста (где одинаковый конфиг) это все делаешь?

phpinfo заявляет что cURL 7.52.1, OpenSSL/1.0.2u

После всего оказалось что его попускает если указать User-Agent в запросе (хотя в этом коде, использующем API не первый год, его никогда не было. В общем решил пока не воевать с origin, если CloudFlare не станет спонтанно блокировать запросы то можно будет работать через него.

Надо смотреть конечно, но владелец домена где лежит апи думаю чёт накрутил в правилах кф.

Интересно :)

Имхо ты на клиенте что-то намудрил, 520 при запросе от любого клиента к кф вообще быть не должно.

caoutchouckcha
()
Последнее исправление: caoutchouckcha (всего исправлений: 1)
Ответ на: комментарий от Dima_228

Короч я не особо понимаю, почему тебе тот айпи сервера, к которому коннектишься напрямую, отдает серт клаудфларе.

Ты точно адресом не ошибся?

консольный curl

А с ним вообще все сложно, у меня он -4 флаг игнорит например и упорно стучит по ipv6. У тебя может резолвит домен иначе, чем php curl, и ходят по разным адресам, в итоге один работает, а второй нет.

Ну и вопрос выше, про то что почему серт кф отдает хост куда стучишь - интересный.

caoutchouckcha
()
Последнее исправление: caoutchouckcha (всего исправлений: 3)