Записки
Nodejs и самоподписанный сертификат в Windows
Проблема
Вам надо сделать запрос из Nodejs приложения к API с самоподписанным сертификатом. Вы такой: —«Изи-пизи! Сейчас установлю свои серты простым батником и всё будет работать!»
certutil -addstore Root YOUR-COMPANY-root.crt
certutil -addstore CA YOUR-COMPANY-intermediate.crt
Но вот не задача: Nodejs не использует системное хранилище сертификатов, поэтому у приложений запущенных локально возникнут проблемы с запросами к API подписанными вашим сертификатом: UNABLE_TO_GET_ISSUER_CERT_LOCALLY.
Вот как на скрине:
Решения
Вариант №1: Код
Передать свой сертификат в Nodejs можно с помощью кода ниже. Если не погружаться в дебри модели OSI и внутренности Node.js (а я не погружался), то он определяет статический метод createSecureContext который используется некоторыми внутренними функциями для создания защищённого соединения. Просто передаёте путь до сертификата в переменную окружения CERTIFICATE и пользуетесь на здоровье.
import fs from 'fs'
import tls from 'tls'
const origCreateSecureContext = tls.createSecureContext
if (process.env.NODE_ENV == 'development') {
tls.createSecureContext = options => {
const certPath = process.env.CERTIFICATE
if (!certPath) {
throw new Error(`Certificate path is not defined!`)
}
const resolvedPath = path.resolve(__dirname, certPath)
if (certPath && fs.existsSync(resolvedPath)) {
const secureContext = origCreateSecureContext(options)
const pem = fs
.readFileSync(resolvedPath, {
encoding: 'ascii'
})
.replace(/\r\n/g, '\n')
const certs = pem.match(
/-----BEGIN CERTIFICATE-----\n[\s\S]+?\n-----END CERTIFICATE-----/g
)
if (!certs) {
throw new Error(`Could not parse certificate «${certPath}»`)
}
certs.forEach(cert => {
secureContext.context.addCACert(cert.trim())
})
return secureContext
}
throw new Error(`Could not find certificate path «${certPath}»`)
}
}
// const app = express() //дальше идёт ваш обычный код
Это работает, но это костыль, который надо вставлять в каждый ваш проект.
Вариант №2: отключение строгой проверки
Подумаешь путь до корневого сертификата не будет так строго проверяться? Что плохого может случиться? Просто ставим переменную окружения set NODE_TLS_REJECT_UNAUTHORIZED=0 и всё! Да, Node.js будет спамить нам сообщениями об этой переменной в консоль, но кого это волнует? MitM? Не, не слышал.
Чушь. Поехали дальше…
Вариант №3: для тех у кого webpack dev server
Ставим в конфиге secure: false и все наши запросы гоняются по открытому каналу. Смотри выше и choose your destiny, как говорится.
Пример из документации Webpack:
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'https://other-server.example.com',
secure: false,
},
},
},
};
Вариант №4: переменная окружения
Берём наш корневой сертификаты и кладём его в какую-нибудь папку которую вы случайно не удалите:
C:\Users\%ИМЯРЕК%\AppData\Shared\certs
(такой папки в системе нет, если что, я сам создал) и запоминаем
любым удобным для Вас способом путь до него.
Открываем настройки системы:
В появившемся окне жмём “Создать”
Вводим имя переменной NODE_EXTRA_CA_CERTS
значение
C:\Users\%ИМЯРЕК%\AppData\Shared\certs\наш-корневой-сертификат.crt
(не забываем про расширение файла!),
далее OK → OK
Переменная будет доступна В НОВОМ инстансе CMD:
Поздравляю, проблема решена! Вы великолепны!