Почему requestjs отклоняет самозаверяющий сертификат SSL, который работает с Firefox?

Вот ситуация. Я создал самозаверяющий сертификат CA и использовал его для подписи второго сертификата для использования с https. Веб-сервер nginx выполняет SSL-завершение и обратное проксирование в приложение expressjs. Чтобы проверить правильность цепочки доверия, я установил CA в Firefox и смог получить доступ к веб-сайту через https без предупреждений, как и ожидалось. Кроме того, я могу проверить сертификат сервера с openssl x509 -in server.crt -text -nooutи я вижу как ожидаемого эмитента, так и, в частности, ожидаемое общее имя для субъекта. (Примечание: используемое здесь общее имя - это IP-адрес, на случай, если это может вызвать проблемы.)

Однако, когда я пытаюсь получить доступ к серверу через скрипт nodejs с помощью requestjs, все идет не так гладко. В сценарии сертификат CA загружается с использованием следующего кода:

request.get({url: theUrl, ca: fs.readFileSync("./ca.crt")}, ...

Но я получаю эту ошибку (строка разорвана для удобства чтения, оригинал - одна строка):

Contacting doorman failed: Error: Hostname/IP doesn't match certificate's altnames: 
"IP: <redacted> is not in the cert's list: "

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

Как я могу заставить requestjs/nodejs доверять этому сертификату?


Содержимое сертификата сервера, как сообщается openssl x509 -text

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number: 3 (0x3)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=State, L=City, O=Company, CN=www.company.com
        Validity
            Not Before: Dec  7 17:19:51 2015 GMT
            Not After : Oct 14 17:19:51 2025 GMT
        Subject: C=US, ST=State, L=City, O=Company, CN=1.2.3.4/emailAddress=webmaster@company.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    ...
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         ...

И файл конфигурации, используемый для генерации этого сертификата:

[ req ]
default_bits       = 4096
prompt             = no
encrypt_key        = no

distinguished_name = req_distinguished_name
req_extensions     = v3_req

[ req_distinguished_name ]
countryName            = "US"
stateOrProvinceName    = "State"
localityName           = "City"
organizationName       = "Company"
commonName             = "1.2.3.4"
emailAddress           = "webmaster@company.com"

[ v3_req ]
subjectAltName = IP:1.2.3.4

1 ответ

Решение

Имя хоста /IP не совпадает с альтернативными именами сертификатов:

Я предполагаю, что ваш сертификат содержит правильное имя хоста, используемое в URL-адресе только как субъект (CN), а не как альтернативное имя субъекта (SAN), но что оно содержит другие имена как SAN. Стандарт совершенно ясен, что если даны альтернативные DNS-имена субъектам, CN не должен проверяться, но в любом случае большинство браузеров проверяют CN (я думаю, Safari более строг). Но node.js реализует строгое поведение и, таким образом, потерпит неудачу.

Если мое предположение верно (трудно увидеть без сертификата), тогда проблему необходимо исправить, создав правильный сертификат. Другая возможность заключается в том, что вы используете немного разные URL в браузере и nodejs (как с и без www префикс).

РЕДАКТИРОВАТЬ: увидев, какой сертификат вы на самом деле используете....

У вас есть сертификат с IP-адресом в CN. Хотя это также поддерживается большинством браузеров, это не правильно. IP-адрес должен быть указан как ipadress SAN, а не как CN. Nodejs ожидает этого только там, и я думаю, что Safari также такой строгий. Обратите внимание, что для IE вы должны поместить его либо в CN, либо в качестве записи SAN dnsname только потому, что им нравится вести себя противоречащим стандарту и в этом случае. Таким образом, чтобы быть в безопасности, поместите его как ipaddress, dnsname и, возможно, как CN тоже.

Другие вопросы по тегам