Подтвердить что ты не робот

Почему Ruby не может проверить сертификат SSL?

Это мой первый раз, когда я пытаюсь использовать библиотеку XMLRPC:: Client для взаимодействия с удаленным API, и я продолжаю получать эту ошибку:

warning: peer certificate won't be verified in this SSL session

Поиск вокруг Я нашел множество людей, которые получили эту ошибку. Обычно это с самозаверяющими сертификатами, и они просто хотят, чтобы он ушел, поэтому они делают что-то грязное, как обезьяна, так, как XMLRPC:: Client открывает его http-сеанс.

Я сначала предположил, что это был просто клиент, не заботящийся о том, был ли сертификат действительным или нет, поэтому я продолжил поиск и наткнулся на этот камень, Он просто заставляет проверять все сертификаты SSL и выдает жесткую ошибку, если она тоже не подходит. Это было именно то, что я хотел. Я включил его, снова запустил код, и теперь я получаю следующее:

OpenSSL:SSL::SSLError:
  SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B:
  certificate verify failed

Конечно! Сертификат плохой! Но я дважды проверяю, чтобы убедиться, что openssl встроен в s_client так:

openssl s_client -connect sub.example.com:443

и что я получу:

CONNECTED(00000003)
---
Certificate chain
<snip>
Verify return code: 0 (ok)

Итак, теперь мы переходим к моему вопросу. OpenSSL (версия командной строки) говорит, что сертификат хорош. OpenSSL (библиотека Ruby) не согласен. Все мои веб-браузеры говорят, что сертификат хорош.

Несколько дополнительных деталей, которые могут быть полезны. Сертификат является подстановочным знаком, но действителен для домена. Параметр openssl s_client выполнялся на тех же машинных секундах, что и код Ruby. Это Ruby 1.8.7 p357, который установлен с RVM.

Использует ли Ruby что-то другое, кроме пакета CA, предоставленного операционной системой хоста? Есть ли способ сказать Ruby использовать конкретный комплект СА или системный?

4b9b3361

Ответ 1

Если вас интересует только то, как заставить Ruby вести себя так же, как OpenSSL s_client или ваш браузер, вы можете перейти к самому последнему разделу, я расскажу о мелкой печати в следующем.

По умолчанию OpenSSL::X509::Store, используемый для подключения, вообще не использует доверенных сертификатов. Основываясь на ваших знаниях о домене приложения, вы обычно пишете экземпляр X509::Store с доверенным сертификатом (сертификатами), которые имеют отношение к вашему приложению. Для этого есть несколько вариантов:

  • Store # add_file принимает путь к сертификату, закодированному PEM/DER
  • Store # add_cert принимает экземпляр X509:: Certificate
  • Store # add_path принимает путь к каталогу, в котором могут быть найдены надежные сертификаты

Подход "Браузер"

Это отличается от браузеров захода на посадку, Java (cacerts) или Windows со своим собственным внутренним хранилищем доверенных сертификатов. Там программное обеспечение предварительно оборудовано набором доверенных сертификатов, который считается "хорошим", по мнению поставщика программного обеспечения. Как правило, это неплохая идея, но если вы действительно заглянете в эти наборы, то вы скоро заметите, что существует слишком много сертификатов. Человек не может действительно сказать, следует ли доверять всем этим сертификатам вслепую или нет.

Подход Ruby

Требования вашего типичного приложения Ruby, с другой стороны, сильно отличаются от требований вашего браузера. Браузер должен быть в состоянии позволить вам перейти на любой "законный" веб-сайт, который поставляется с сертификатом TLS и обслуживается через https. Но в типичном приложении Ruby вам придется иметь дело только с несколькими службами, использующими TLS, или в противном случае требовать проверки сертификата.

И есть преимущество подхода Ruby - хотя для этого требуется более ручная работа, в конечном итоге вы получите ручное решение, которое точно доверяет сертификатам, которым он должен доверять в вашем конкретном контексте приложения. Это утомительно, но безопасность намного выше, потому что вы подвергаете намного меньше поверхности атаки. Возьмите последние события: если вам никогда не приходилось включать DigiNotar или любой другой скомпрометированный корень в ваш набор доверия, тогда нет таких нарушений, которые могут повлиять на вас.

Однако, как вы уже заметили, недостатком этого является то, что по умолчанию, если вы не активно добавляете доверенные сертификаты, расширение OpenSSL вообще не сможет проверять какой-либо одноранговый сертификат. Чтобы все было в порядке, вам нужно настроить конфигурацию вручную.

Это неудобство привело к множеству сомнительных мер, чтобы обойти его, а самое худшее - глобально установить OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE. Пожалуйста, не делайте этого. Мы даже шутили о добавлении кода, который позволяет вашему приложению разбиваться случайным образом, если мы сталкиваемся с этим взломом:)

Если ручная настройка доверия кажется слишком сложной, теперь я предлагаю легкую альтернативу, которая делает расширение OpenSSL вести себя точно так же, как команды CLI OpenSSL, такие как s_client.

Почему s_client может проверить сертификат

OpenSSL использует аналогичный подход для браузеров и Windows. Типичная установка поместит на ваш жесткий диск набор доверенных сертификатов (что-то вроде /etc/ssl/certs/ca-bundle.crt), и это будет служить стандартным набором доверенных сертификатов. Что там, где s_client выглядит, когда нужно проверять одноранговые сертификаты и почему ваш эксперимент преуспел.

Приведение Ruby как s_client

Если вы все равно хотите иметь такой же комфорт при проверке сертификатов с Ruby, вы можете сказать, что он использует пакет доверенных сертификатов OpenSSL, если он доступен в вашей системе, вызывая OpenSSL::X509::Store#set_default_paths. Дополнительную информацию можно найти здесь. Чтобы использовать это с помощью XMLRPC::Client, просто убедитесь, что set_default_paths вызывается в X509::Store, который он использует.

Ответ 2

Если у вас есть файл ca-certificate, просто выполните следующее:

http.ca_file = <YOUR CA-CERT FILE PATH>
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_depth = 5