Перейти к содержимому
ecdsa.com
curl (OpenSSL backend)curl

Сообщение об ошибке

curl: (60) SSL certificate problem: self-signed certificate

Также выводится как

  • curl: (60) SSL certificate problem: self signed certificate
  • curl: (60) SSL certificate OpenSSL verify result: self-signed certificate (18)

OpenSSL 3.0 и новее выводят «self-signed certificate», OpenSSL 1.1.1 — «self signed certificate». Более новые версии curl (8.22.0 в нашей проверке) формулируют это как «SSL certificate OpenSSL verify result: self-signed certificate (18)». Не путайте эту ошибку с «self-signed certificate in certificate chain»: там есть цепочка CA, которая заканчивается недоверенным корневым сертификатом.

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (18)

Что это означает

Сервер предъявил единственный сертификат, подписанный его собственным ключом (издатель совпадает с субъектом), а именно этого сертификата в хранилище доверенных сертификатов curl нет. За ним не стоит CA, который curl мог бы найти, поэтому проверка останавливается на глубине 0. Для серверов разработки и специализированных устройств это нормально, и установка промежуточного сертификата здесь никогда не помогает.

Почему это происходит

Как исправить

  1. 1.

    Доверяйте именно этому сертификату, предварительно проверив его

    Для одного внутреннего эндпоинта сохраните сертификат, сверьте его отпечаток SHA-256 по доверенному каналу (консоль устройства, администратор, который его создал) и передайте его через --cacert. Тогда curl в этом вызове примет только этот сертификат и никакой другой.

    bash
    # Fetch the certificate once, compare its fingerprint out of band, then trust exactly that file
    openssl s_client -connect api.example.com:8443 -servername api.example.com </dev/null 2>/dev/null \
      | openssl x509 -out api.example.com.pem
    openssl x509 -in api.example.com.pem -noout -fingerprint -sha256
    curl --cacert api.example.com.pem https://api.example.com:8443/
  2. 2.

    При разработке: выпускайте сертификаты от локального CA

    Локальный CA (mkcert, step-ca или созданный вручную корневой сертификат) позволяет один раз настроить доверие к одному корневому сертификату и выпускать сертификаты для любого числа хостов разработки. Такие сертификаты уже не самоподписанные, поэтому ошибка исчезает везде, где установлен корневой сертификат.

    bash
    # mkcert creates a local CA, installs it into the system and browser stores,
    # and issues certificates signed by it (no longer self-signed)
    mkcert -install
    mkcert api.example.test localhost 127.0.0.1
  3. 3.

    Для публичных хостов: установите сертификат от публичного CA

    Всем сервисам, к которым обращаются другие люди или сторонние клиенты, следует предъявлять сертификат от публично доверенного CA; ACME-клиенты, такие как certbot, lego или Caddy, получают и продлевают его автоматически.

    bash
    # Public names: get a certificate from a public CA, e.g. with certbot (ACME)
    sudo certbot certonly --nginx -d api.example.com
  4. 4.

    Временная диагностика: обратитесь к сервису с отключённой проверкой

    С -k curl пропускает проверку сертификатов, поэтому ответ 200 подтверждает, что не хватает только доверия. Не оставляйте этот флаг: самоподписанный сертификат, принятый без проверки, в любой момент можно подменить сертификатом злоумышленника, и curl этого не заметит.

    bash
    # Diagnostic only: confirms the service answers when certificate checks are skipped
    curl -sS -k -o /dev/null -w '%{http_code}\n' https://api.example.com:8443/

Связанные ошибки

Открыть всю базу ошибок подписей