Узел.JS Hostname / IP не совпадает с altnames сертификата
У меня есть код:
var r = require('request');
r({
method: 'POST',
url: 'https://api.dropbox.com'},
function() { console.log(arguments) } )
Когда я запускаю его на рабочем столе с узлом 0.9.4, я получаю это в консоли:
{ '0': [Error: Hostname/IP doesn't match certificate's altnames] }
Когда я запускаю его на нетбуке с узлом 0.6.12, все это работает без ошибок (302 ответа - я думаю, что это правильно).
В рассматриваемом узле .JS hostname / IP не соответствует сертификатам altnames , Rojuinex пишет: "Да, проблема с браузером... огорченный". Что означает "проблема браузера"?
UPD. Эта проблема была решена после отката на узле v0. 8
8 ответов:
Начиная с 0.9.2 (включая 0.10.x) узел.js теперь проверяет сертификаты по умолчанию. Вот почему вы можете видеть, что он становится более строгим, когда вы обновляете прошлый узел.Яш 0.8. (HT: https://github.com/mscdex/node-imap/issues/181#issuecomment-14781480 )
Вы можете избежать этого с помощью опции
{rejectUnauthorized:false}, однако это имеет серьезные последствия для безопасности. Все, что вы посылаете одноранговому узлу, по-прежнему будет зашифровано, но гораздо легче организовать атаку "человек в середине", т. е. ваши данные будут зашифрованы для однорангового узла, но сам узел-это не тот сервер, о котором вы думаете!Было бы лучше сначала диагностировать, почему сертификат не авторизуется, и посмотреть, можно ли это исправить.
Немного обновленный ответ (поскольку я столкнулся с этой проблемой в разных обстоятельствах.)
Когда вы подключаетесь к серверу с помощью SSL, первое, что делает сервер, - это предоставляет сертификат, который говорит: "Я есмь api.dropbox.com "сертификат имеет "субъект", а субъект имеет " CN "(сокращение от "общее имя".) Сертификат также может иметь одно или несколько "имен субъектов". Когда узел.js подключается к серверу, узлу.js получает этот сертификат, а затем проверяет, что доменное имя его думает, что он подключается к (api.dropbox.com) соответствует либо CN субъекта, либо одному из имен altnames. Обратите внимание, что в узле 0.10.x, если вы подключаетесь с помощью IP, IP-адрес должен быть в узле altnames - node.js не будет пытаться проверить IP против CN.
Установка флага
rejectUnauthorizedв false позволит обойти эту проверку, но, во-первых, если сервер выдает вам другие учетные данные, чем вы ожидаете, происходит что-то подозрительное, а во-вторых, это также обойдет другие проверки - это не очень хорошая идея, если вы подключаетесь через Интернет.Если вы используете узел > = 0.11.x, вы также можете указать a
checkServerIdentity: function(host, cert)функция к модулю tls, который должен возвратитьundefined, Если вы хотите разрешить соединение и бросить исключение в противном случае (хотя я не знаю, будет лиrequestпрокси этот флаг через tls для вас.) Это может быть удобно, чтобы объявить такую функцию иconsole.log(host, cert);, чтобы выяснить, что, черт возьми, происходит.
В случае, если вы используете пакет http-proxy, это происходит, когда ваш сервер является HTTP (например, localhost), а целевой-HTTPS. Чтобы устранить эту проблему, установите значение changeOrigin в true.
const proxy = httpProxy.createProxyServer(); proxy.web(req, res, { changeOrigin: true, target: https://example.com:3000, });В случае, если ваш сервер HTTPS и целевой также HTTPS, вы должны включить сертификат SSL
httpProxy.createServer({ ssl: { key: fs.readFileSync('valid-ssl-key.pem', 'utf8'), cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8') }, target: 'https://example.com:3000', secure: true }).listen(443);
Я знаю, что это старый, но для тех, кто ищет:
Удалите https:// из имени хоста и добавьте вместо него порт 443.
{ method: 'POST', hostname: 'api.dropbox.com', port: 443 }
У меня была та же проблема с использованием модуля запроса для прокси POST запроса из другого места, и это было потому, что я оставил свойство хоста в заголовке (я копировал заголовок из исходного запроса).
Другой способ исправить это в других обстоятельствах-использовать
NODE_TLS_REJECT_UNAUTHORIZED=0в качестве переменной окружения
NODE_TLS_REJECT_UNAUTHORIZED=0 node server.js
У нас нет этой проблемы, если мы тестируем наш запрос клиента с адресом назначения
localhost(hostилиhostnameна узле.js)и наше общее имя сервераCN = localhostв сертификате сервера. Но даже если мы изменимlocalhostна127.0.0.1или любой другой IP, мы получим ошибкуHostname/IP doesn't match certificate's altnamesна узле.js илиSSL handshake failedна QT.У меня была такая же проблема с моим сертификатом сервера по запросу клиента. Чтобы решить ее на моем клиентском узле.JS app мне нужно было поставить
subjectAltNameна мойserver_extensionсо следующим значение:[ server_extension ] . . . subjectAltName = @alt_names_server [alt_names_server] IP.1 = x.x.x.xИ затем я использую
-extension, Когда я создаю и подписываю сертификат.Пример:
В моем случае , я сначала экспортирую конфигурационный файл эмитента, потому что этот файл содержит
server_extension:export OPENSSL_CONF=intermed-ca.cnfПоэтому я создаю и подписываю свой сертификат сервера:
openssl ca \ -in server.req.pem \ -out server.cert.pem \ -extensions server_extension \ -startdate `date +%y%m%d000000Z -u -d -2day` \ -enddate `date +%y%m%d000000Z -u -d +2years+1day`Он прекрасно работает на клиентах, основанных на узле.js с https запросами, но он не работает с клиентами, основанными на QT QSsl, когда мы определяем
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer), если мы не используемQSslSocket::VerifyNone, он не будет работать. Если мы используемVerifyNoneэто заставит наше приложение не проверять сертификат peer, поэтому оно примет любой сертификат. Таким образом, чтобы решить эту проблему, мне нужно изменить общее имя моего сервера на его cert и заменить его значение на IP-адрес, где работает мой сервер.Например:
CN = 127.0.0.1
После проверки того, что сертификат выдан известным центром сертификации (CA), будут проверены альтернативные имена субъектов или общее имя, чтобы убедиться, что имя хоста совпадает. Это находится в функцииcheckServerIdentity . Если сертификат имеет альтернативные имена субъектов, а имя хоста отсутствует в списке, вы увидите сообщение об ошибке, описанное ниже:
Имя хоста / IP не соответствует именам сертификатов
Если у вас есть сертификат CA это используется для создания сертификата, который вы используете (обычно это происходит при использовании самозаверяющих сертификатов), это может быть предоставлено с помощью
var r = require('request'); var opts = { method: "POST", ca: fs.readFileSync("ca.cer") }; r('https://api.dropbox.com', opts, function (error, response, body) { // do something });Это подтвердит, что сертификат выдан предоставленным Центром сертификации, но проверка имени хоста все равно будет выполнена. Достаточно просто указать CA, если сертификат содержит имя хоста в альтернативных именах субъекта. Если это не так, и вы также хотите пропустить проверку имени хоста, вы можете передать функцию noop для
checkServerIdentityvar r = require('request'); var opts = { method: "POST", ca: fs.readFileSync("ca.cer"), agentOptions: { checkServerIdentity: function() {} } }; r('https://api.dropbox.com', opts, function (error, response, body) { // do something });
Comments