Вопрос касается использования самозаверяющих сертификатов при разработке локального полного стека (в данном случае приложения React и сервера Node.js FE).
Обратите внимание , что сам вопрос вероятно, не так сложно, как можно предположить по длине. Просто мне нужно было описать всю настройку, чтобы избежать несущественных тривиальных предложений. Кроме того, когда / если на вопрос дан ответ, он должен послужить хорошей отправной точкой для таких начинаний.
Причина
Многие функции, включая, но не ограничиваясь совместно используемые подписанные файлы cookie, http2 и т. Д. c ... работают только по протоколу HTTPS или требуют настройки родственного / родительского домена, что вызывает необходимость создания сертификата и запуска Web-сервера Dev Server и Nodejs Сервер FE через HTTPS (локально) на доменах экспликации, а не на localhost
.
Обратите внимание , что проблема заключается в c для локальной разработки, так как он правильно настроен с не самоподписанные сертификаты и более HTTPS в производстве.
Предположение
Хотя возможно создать «нормальный» сертификат, используя что-то вроде Let's Encrypt, это не так всегда возможно или желательно (политика компании или что-то подобное).
По этой причине и ради академических целей c мы решили использовать самозаверяющий сертификат .
Настройка
ОС: Ma c Catalina 10.15.2 Узел: 13,8
Есть два поддоменов:
app.mylocaldomain.com
, которые размещает приложение React через Webpack Dev Server api.mylocaldomain.com
, на котором размещается сервер API FE через Node.js + Express
необходимо
Быть в состоянии сделать HTTPS AJAX запрос от https://app.mylocaldomain.com
до https://api.mylocaldomain.com/some-route
Шаги
Добавить app.mylocaldomain.com
и app.mylocaldomain.com
до /etc/hosts
...
127.0.0.1 api.mylocaldomain.com
127.0.0.1 app.mylocaldomain.com
...
Создать api/req.cnf
файл
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = State
L = Location
O = myorg
OU = myunit
CN = api.mylocaldomain.com
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = api.mylocaldomain.com
Создать app/req.cnf
файл
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = State
L = Location
O = myorg
OU = myunit
CN = app.mylocaldomain.com
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = app.mylocaldomain.com
Создать Приложение cert.key
и cert.pem
файлы:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout app/cert.key -out app/cert.pem -config app/req.cnf -sha256
Создать API cert.key
и cert.pem
файлы:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout api/cert.key -out api/cert.pem -config api/req.cnf -sha256
Загрузите оба сертификата в Ma c Доступ к цепочке для ключей и подтвердите, что оба доверяют
Это является рабочим результатом с обоими сертификатами, утвержденными в цепочке для ключей:
![enter image description here](https://i.stack.imgur.com/bHIyD.png)
Настройка приложения Webpack D ev сервер для запуска через HTTPS
devServer: {
...
host: 'app.mylocaldomain.com',
port: 443,
https: {
key: FS.readFileSync('/path/to/app/cert.key'),
cert: FS.readFileSync('/path/to/app/cert.pem')
},
...
}
Запустите приложение с sudo yarn start
(webpack-dev-server
в npm сценариях), чтобы разрешить использование 443
port
Это рабочий результат:
![enter image description here](https://i.stack.imgur.com/7DBnG.png)
, где приложение правильно загружено по HTTPS.
Примечание что пропуск sudo
приводит к следующему (или аналогичному, в зависимости от настроек вашего Dev-сервера Webpack):
...
Error: listen EACCES: permission denied 127.0.0.1:443
...
Настройка сервера FE для запуска по HTTPS
...
const app = express(...)
...
const key = fs.readFileSync('/path/to/api/cert.key');
const cert = fs.readFileSync('/path/to/api/cert.pem');
https.createServer({key, cert}, app).listen(PORT, error => {
if (!error) {
console.info(`Listening on port: ${PORT}`);
} else {
console.error(error);
}
});
...
Запустить сервер API FE с помощью sudo yarn start --open --public api.mylocaldomain.com --port 443
(node lib/
в npm скриптах)
yarn run v1.22.0
$ node lib/ --public api.mylocaldomain.com
Listening on port: 5000
Проблема
Приведенных выше настроек должно быть достаточно, однако вызов запроса AJAX для https://api.mylocaldomain.com/status
(да, маршрут существует) вызывает следующую (сокращенную для ясности) ошибку в консоли Chrome :
GET https://api.mylocaldomain.com/status
net::ERR_CERT_COMMON_NAME_INVALID
Если бы вы получили прямой доступ к https://api.mylocaldomain.com/status
в Chrome, вы получили бы следующее:
![enter image description here](https://i.stack.imgur.com/m9S0T.png)
Это предполагает, что сертификаты для App и API несколько смешались , но я несколько раз выполнял вышеупомянутые шаги в различных перестановках и не видел, как это произойдет. Возможно, /etc/hosts
картографирование это испортило? Это имело бы смысл, так как app.
и api.
отображаются в 127.0.0.1
, создавая путаницу. Однако я не согласен с тем, как решить эту проблему.
Действительно, при проверке кажется, что Chrome (по крайней мере) загружает сертификат приложения при обращении к API. Почему?
Переход по ссылке выше приводит к:
![enter image description here](https://i.stack.imgur.com/YrPln.png)
Вызов curl -XGET https://api.mylocaldomain.com/status
вызывает следующую ошибку:
>>> curl -XGET https://api.mylocaldomain.com/status
curl: (60) SSL: no alternative certificate subject name matches target host name 'api.mylocaldomain.com'
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
, что является нечетным, поскольку api.mylocaldomain.com
явно определено в req.cnf
для API выше.
Предложения?
Я предполагаю, что это что-то чрезвычайно крошечное, и я буду смущен тем, что пропустил это, но после нескольких проходов и повторных попыток, оно могло попасть в мое слепое пятно (s).
Приложение A.
Создание многодоменного *.mylocaldomain.com
сертификата также не работает, с ошибкой «недопустимое общее имя» или Invalid Host header
в зависимости от различных настроек.