Почему возникает ошибка при попытке подключиться к серверу, использующему самоподписанный сертификат?

Я выполнил следующие команды: 
<br/> <code>openssl genpkey -algorithm RSA -out localhost.key</code> 
<br/> <br/> <pre><code>openssl req -new -x509 -key localhost.key -out localhost.crt -days 365</code></pre> 
<br/> <br/> <pre><code>sudo cp localhost.crt /etc/pki/ca-trust/source/anchors/</code></pre> 
<br/> <br/> <code>sudo update-ca-trust</code> 
<br/> <br/> <pre><code>openssl verify -CAfile /etc/pki/tls/certs/ca-bundle.crt localhost.crt</code></pre> 
<br/> <br/> Результат: localhost.crt: OK. При этом команда <code>curl https://localhost:8000/</code> работает. 
<br/> <br/> Код сервера: 
<br/> <pre><code class="javascript">'use strict';

const path = require('node:path');
const fsp = require('node:fs/promises');
const http2 = require('node:http2');

const keypath = path.join(__dirname, 'localhost.key');
const certpath = path.join(__dirname, 'localhost.crt');

const tlsOptions = async (keypath, certpath) =&gt; ({
  key: await fsp.readFile(keypath),
  cert: await fsp.readFile(certpath),
});

const main = async () =&gt; {
  const options = await tlsOptions(keypath, certpath);
  const server = http2.createSecureServer(options);
  server.on('stream', (stream) =&gt; {
    stream.respond({ ':status': 200 });
    stream.end('success');
  });
  server.listen(8000);
};

main();</code></pre> 
<br/> <br/> Код клиента: 
<br/> <pre><code class="javascript">'use strict';

fetch('https://localhost:8000/').then(console.log);</code></pre> 
<br/> <br/> Операционная система: Fedora 41. Ошибка: 
<br/> <pre><code>node:internal/deps/undici/undici:13185
      Error.captureStackTrace(err);
            ^

TypeError: fetch failed
    at node:internal/deps/undici/undici:13185:13
    at process.processTicksAndRejections (node:in
  • 22 ноября 2024 г. 15:13
Ответы на вопрос 1
Ошибка при подключении к серверу с использованием самоподписанного сертификата может возникать по нескольким причинам. В вашем случае сервер (который работает на Node.js) использует самоподписанный сертификат, и клиент (также написанный на Node.js) не доверяет этому сертификату по умолчанию.

Вот некоторые возможные причины и способы их устранения:

1. **Отсутствие доверия к сертификату**:
   Node.js по умолчанию не доверяет самоподписанным сертификатам. Если не указать, что клиент должен доверять самоподписанному сертификату, соединение будет отклонено. Вы можете обойти это ограничение, добавив в запрос параметр `agent`, который позволяет явно указать, как обрабатывать сертификаты. Например, используя библиотеку `https`, вы можете настроить клиент на игнорирование ошибок сертификата (что не рекомендуется в продакшене).

    ```javascript
    const https = require('node:https');

    const agent = new https.Agent({
      rejectUnauthorized: false // Сигнализирует, что не надо проверять сертификаты
    });

    fetch('https://localhost:8000/', { agent })
      .then(console.log)
      .catch(console.error);
    ```

2. **Проблемы с версией протокола**:
   Убедитесь, что сервер и клиент используют совместимые версии протоколов (HTTP/2 и HTTPS). Это может потребовать дополнительной настройки, если у вас возникают проблемы с этой частью.

3. **Проблемы с портом и адресом**:
   Убедитесь, что клиент подключается к тому же адресу и порту, где работает сервер. Ваш код сервера использует `localhost:8000`, что должно совпадать с тем, к чему вы обращаетесь в `fetch`.

4. **Запуск клиента**:
   Если код клиента запущен в контексте, где есть ограничения на выполнение небезопасных действий (например, если он выполняется в веб-браузере), он может не разрешить подключение к серверу с самоподписанным сертификатом. В этом случае тестируйте клиентский код на Node.js.

5. **Ошибки в коде**:
   Обратите внимание на точность и правильность используемого в коде. Ошибка также может быть вызвана некорректным использованием API или неправильной настройкой сервера.

Ваше текущее окружение (Fedora 41) и используемые вами команды для создания и установки сертификатов выглядят корректно. Убедитесь, что команду `curl` было выполнено с теми же сертификатами, что используются в Node.js-клиенте, для проверки, работает ли для всех частей системы правильная установка сертификатов.
Похожие вопросы