Использование самоподписанных сертификатов в локальной разработке Node.js / Express / React - PullRequest
0 голосов
/ 24 февраля 2020

Вопрос касается использования самозаверяющих сертификатов при разработке локального полного стека (в данном случае приложения 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

Шаги

  1. Добавить app.mylocaldomain.com и app.mylocaldomain.com до /etc/hosts

    ...
    127.0.0.1   api.mylocaldomain.com
    127.0.0.1   app.mylocaldomain.com
    ...
    
  2. Создать 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
    
  3. Создать 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
    
  4. Создать Приложение 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
    
  5. Создать 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
    
  6. Загрузите оба сертификата в Ma c Доступ к цепочке для ключей и подтвердите, что оба доверяют

    Это является рабочим результатом с обоими сертификатами, утвержденными в цепочке для ключей:

    enter image description here

  7. Настройка приложения 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')
        },
        ...
    }
    
  8. Запустите приложение с sudo yarn start (webpack-dev-server в npm сценариях), чтобы разрешить использование 443 port

    Это рабочий результат:

    enter image description here

    , где приложение правильно загружено по HTTPS.

    Примечание что пропуск sudo приводит к следующему (или аналогичному, в зависимости от настроек вашего Dev-сервера Webpack):

    ...
    Error: listen EACCES: permission denied 127.0.0.1:443
    ...
    
  9. Настройка сервера 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);
        }
    });
    ...
    
  10. Запустить сервер 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

Это предполагает, что сертификаты для App и API несколько смешались , но я несколько раз выполнял вышеупомянутые шаги в различных перестановках и не видел, как это произойдет. Возможно, /etc/hosts картографирование это испортило? Это имело бы смысл, так как app. и api. отображаются в 127.0.0.1, создавая путаницу. Однако я не согласен с тем, как решить эту проблему.

Действительно, при проверке кажется, что Chrome (по крайней мере) загружает сертификат приложения при обращении к API. Почему?

Переход по ссылке выше приводит к:

enter image description here

Вызов 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 в зависимости от различных настроек.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...