Перейти к содержанию

HTTPS

v18.x.x

Стабильность: 2 – Стабильная

АПИ является удовлетворительным. Совместимость с NPM имеет высший приоритет и не будет нарушена кроме случаев явной необходимости.

HTTPS - это протокол HTTP через TLS/SSL. В Node.js он реализован в виде отдельного модуля.

Определение отсутствия поддержки криптографии

Возможно, что Node.js собран без поддержки модуля node:crypto. В таких случаях попытка импорта из https или вызов require('node:https') приведет к ошибке.

При использовании CommonJS возникшую ошибку можно перехватить с помощью try/catch:

1
2
3
4
5
6
let https;
try {
    https = require('node:https');
} catch (err) {
    console.error('Поддержка https отключена!');
}

При использовании лексического ключевого слова ESM import ошибка может быть поймана только в том случае, если обработчик process.on('uncaughtException') зарегистрирован до любой попытки загрузить модуль (например, с помощью модуля предварительной загрузки).

При использовании ESM, если есть вероятность, что код может быть запущен на сборке Node.js, в которой не включена поддержка криптографии, используйте функцию import() вместо лексического ключевого слова import:

1
2
3
4
5
6
let https;
try {
    https = await import('node:https');
} catch (err) {
    console.error('Поддержка https отключена!');
}

Класс: https.Agent

Объект Agent для HTTPS, аналогичный http.Agent. Дополнительную информацию смотрите в https.request().

new Agent([options])

  • options <Object> Набор конфигурируемых опций для установки на агента. Может иметь те же поля, что и для http.Agent(options), и

    • maxCachedSessions <number> максимальное количество TLS кэшированных сессий. Используйте 0, чтобы отключить кэширование сессий TLS. По умолчанию: 100.

    • servername <string> значение расширения Server Name Indication extension для отправки на сервер. Используйте пустую строку '', чтобы отключить отправку расширения. По умолчанию: имя хоста целевого сервера, если только целевой сервер не указан с помощью IP-адреса, в этом случае по умолчанию используется '' (без расширения).

      Информацию о повторном использовании сеанса TLS см. в Session Resumption.

Событие: keylog

  • line <Buffer> Строка текста ASCII, в формате NSS SSLKEYLOGFILE.
  • tlsSocket {tls.TLSSocket} Экземпляр tls.TLSSocket, на котором оно было сгенерировано.

Событие keylog испускается, когда ключевой материал генерируется или принимается соединением, управляемым этим агентом (обычно до завершения рукопожатия, но не обязательно). Этот ключевой материал может быть сохранен для отладки, поскольку он позволяет расшифровать захваченный трафик TLS. Он может выдаваться несколько раз для каждого сокета.

Типичный случай использования - добавление полученных строк в общий текстовый файл, который впоследствии используется программами (например, Wireshark) для расшифровки трафика:

1
2
3
4
5
6
// ...
https.globalAgent.on('keylog', (line, tlsSocket) => {
    fs.appendFileSync('/tmp/ssl-keys.log', line, {
        mode: 0o600,
    });
});

Класс: https.Server

  • Расширяет: {tls.Server}

Дополнительную информацию смотрите в http.Server.

server.close([callback])

  • callback <Function>
  • Возвращает: {https.Server}

См. server.close() в модуле node:http.

server.closeAllConnections()

Смотрите server.closeAllConnections() в модуле node:http.

server.closeIdleConnections()

Смотрите server.closeIdleConnections() в модуле node:http.

server.headersTimeout

  • <number> По умолчанию: 60000.

Смотрите server.headersTimeout в модуле node:http.

server.listen()

Запускает HTTPS-сервер, прослушивающий зашифрованные соединения. Этот метод идентичен server.listen() из net.Server.

server.maxHeadersCount

  • <number> По умолчанию: 2000.

Смотрите server.maxHeadersCount в модуле node:http.

server.requestTimeout

  • <number> По умолчанию: 300000.

Смотрите server.requestTimeout в модуле node:http.

server.setTimeout([msecs][, callback])

  • msecs <number> По умолчанию: 120000 (2 минуты)
  • callback <Function>
  • Возвращает: {https.Server}

См. server.setTimeout() в модуле node:http.

server.timeout

  • <number> По умолчанию: 0 (без таймаута).

Смотрите server.timeout в модуле node:http.

server.keepAliveTimeout

  • <number> По умолчанию: 5000 (5 секунд)

Смотрите server.keepAliveTimeout в модуле node:http.

https.createServer([options][, requestListener])

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// curl -k https://localhost:8000/
const https = require('node:https');
const fs = require('node:fs');

const options = {
    key: fs.readFileSync(
        'test/fixtures/keys/agent2-key.pem'
    ),
    cert: fs.readFileSync(
        'test/fixtures/keys/agent2-cert.pem'
    ),
};

https
    .createServer(options, (req, res) => {
        res.writeHead(200);
        res.end('hello world\n');
    })
    .listen(8000);

Или

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const https = require('node:https');
const fs = require('node:fs');

const options = {
  pfx: fs.readFileSync('test/fixtures/test_cert.pfx'),
  парольная фраза: 'sample',
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
}).listen(8000);

https.get(options[, callback])

https.get(url[, options][, callback])

  • url {строка | URL}
  • options {Object | string | URL} Принимает те же опции, что и https.request(), с методом, всегда установленным на GET.
  • callback <Function>

Подобно http.get(), но для HTTPS.

options может быть объектом, строкой или объектом URL. Если options является строкой, она автоматически разбирается с помощью new URL(). Если это объект URL, он будет автоматически преобразован в обычный объект options.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const https = require('node:https');

https
    .get('https://encrypted.google.com/', (res) => {
        console.log('statusCode:', res.statusCode);
        console.log('headers:', res.headers);

        res.on('data', (d) => {
            process.stdout.write(d);
        });
    })
    .on('error', (e) => {
        console.error(e);
    });

https.globalAgent

Глобальный экземпляр https.Agent для всех запросов HTTPS клиентов.

https.request(options[, callback])

  • url {строка | URL}
  • options {Object | string | URL} Принимает все опции из http.request(), с некоторыми различиями в значениях по умолчанию:
    • protocol Default: 'https:'.
    • port По умолчанию: 443
    • agent По умолчанию: https.globalAgent
  • callback <Function>
  • Возвращает: {http.ClientRequest}

Делает запрос на защищенный веб-сервер.

Также принимаются следующие дополнительные опции из tls.connect(): ca, cert, ciphers, clientCertEngine, crl, dhparam, ecdhCurve, honorCipherOrder, key, passphrase, pfx, rejectUnauthorized, ecureOptions, ecureProtocol, servername, essionIdContext, highWaterMark.

options может быть объектом, строкой или объектом URL. Если options - строка, она автоматически разбирается с помощью new URL(). Если это объект URL, то он будет автоматически преобразован в обычный объект options.

https.request() возвращает экземпляр класса http.ClientRequest. Экземпляр ClientRequest представляет собой поток, доступный для записи. Если нужно загрузить файл с помощью POST-запроса, то пишите в объект ClientRequest.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
const https = require('node:https');

const options = {
    hostname: 'encrypted.google.com',
    port: 443,
    path: '/',
    method: 'GET',
};

const req = https.request(options, (res) => {
    console.log('statusCode:', res.statusCode);
    console.log('headers:', res.headers);

    res.on('data', (d) => {
        process.stdout.write(d);
    });
});

req.on('error', (e) => {
    console.error(e);
});
req.end();

Пример использования опций из tls.connect():

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const options = {
    hostname: 'encrypted.google.com',
    port: 443,
    path: '/',
    method: 'GET',
    key: fs.readFileSync(
        'test/fixtures/keys/agent2-key.pem'
    ),
    cert: fs.readFileSync(
        'test/fixtures/keys/agent2-cert.pem'
    ),
};
options.agent = new https.Agent(options);

const req = https.request(options, (res) => {
    // ...
});

В качестве альтернативы откажитесь от пула соединений, не используя Agent.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const options = {
    hostname: 'encrypted.google.com',
    port: 443,
    path: '/',
    method: 'GET',
    key: fs.readFileSync(
        'test/fixtures/keys/agent2-key.pem'
    ),
    cert: fs.readFileSync(
        'test/fixtures/keys/agent2-cert.pem'
    ),
    agent: false,
};

const req = https.request(options, (res) => {
    // ...
});

Пример с использованием URL в качестве options:

1
2
3
4
5
const options = new URL('https://abc:xyz@example.com');

const req = https.request(options, (res) => {
    // ...
});

Пример привязки к отпечатку пальца сертификата или открытому ключу (аналогично pin-sha256):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
const tls = require('node:tls');
const https = require('node:https');
const crypto = require('node:crypto');

function sha256(s) {
    return crypto
        .createHash('sha256')
        .update(s)
        .digest('base64');
}
const options = {
    hostname: 'github.com',
    port: 443,
    path: '/',
    method: 'GET',
    checkServerIdentity: function (host, cert) {
        // Make sure the certificate is issued to the host we are connected to
        const err = tls.checkServerIdentity(host, cert);
        if (err) {
            return err;
        }

        // Pin the public key, similar to HPKP pin-sha256 pinning
        const pubkey256 =
            'pL1+qb9HTMRZJmuC/bB/ZI9d302BYrrqiVuRyW+DGrU=';
        if (sha256(cert.pubkey) !== pubkey256) {
            const msg =
                'Certificate verification error: ' +
                `The public key of '${cert.subject.CN}' ` +
                'does not match our pinned fingerprint';
            return new Error(msg);
        }

        // Pin the exact certificate, rather than the pub key
        const cert256 =
            '25:FE:39:32:D9:63:8C:8A:FC:A1:9A:29:87:' +
            'D8:3E:4C:1D:98:DB:71:E4:1A:48:03:98:EA:22:6A:BD:8B:93:16';
        if (cert.fingerprint256 !== cert256) {
            const msg =
                'Certificate verification error: ' +
                `The certificate of '${cert.subject.CN}' ` +
                'does not match our pinned fingerprint';
            return new Error(msg);
        }

        // This loop is informational only.
        // Print the certificate and public key fingerprints of all certs in the
        // chain. Its common to pin the public key of the issuer on the public
        // internet, while pinning the public key of the service in sensitive
        // environments.
        do {
            console.log(
                'Subject Common Name:',
                cert.subject.CN
            );
            console.log(
                '  Certificate SHA256 fingerprint:',
                cert.fingerprint256
            );

            hash = crypto.createHash('sha256');
            console.log(
                '  Public key ping-sha256:',
                sha256(cert.pubkey)
            );

            lastprint256 = cert.fingerprint256;
            cert = cert.issuerCertificate;
        } while (cert.fingerprint256 !== lastprint256);
    },
};

options.agent = new https.Agent(options);
const req = https.request(options, (res) => {
    console.log(
        'All OK. Server matched our pinned cert or public key'
    );
    console.log('statusCode:', res.statusCode);
    // Print the HPKP values
    console.log('headers:', res.headers['public-key-pins']);

    res.on('data', (d) => {});
});

req.on('error', (e) => {
    console.error(e.message);
});
req.end();

Выходные данные, например:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Subject Common Name: github.com
  Certificate SHA256 fingerprint: 25:FE:39:32:D9:63:8C:8A:FC:A1:9A:29:87:D8:3E:4C:1D:98:DB:71:E4:1A:48:03:98:EA:22:6A:BD:8B:93:16
  Public key ping-sha256: pL1+qb9HTMRZJmuC/bB/ZI9d302BYrrqiVuRyW+DGrU=
Subject Common Name: DigiCert SHA2 Extended Validation Server CA
  Certificate SHA256 fingerprint: 40:3E:06:2A:26:53:05:91:13:28:5B:AF:80:A0:D4:AE:42:2C:84:8C:9F:78:FA:D0:1F:C9:4B:C5:B8:7F:EF:1A
  Public key ping-sha256: RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=
Subject Common Name: DigiCert High Assurance EV Root CA
  Certificate SHA256 fingerprint: 74:31:E5:F4:C3:C1:CE:46:90:77:4F:0B:61:E0:54:40:88:3B:A9:A0:1E:D0:0B:A6:AB:D7:80:6E:D3:B1:18:CF
  Public key ping-sha256: WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=
All OK. Server matched our pinned cert or public key
statusCode: 200
headers: max-age=0; pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; pin-sha256="RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho="; pin-sha256="k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws="; pin-sha256="K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q="; pin-sha256="IQBnNBEiFuhj+8x6X8XLgh01V9Ic5/V3IRQLNFFc7v4="; pin-sha256="iie1VXtL7HzAMF+/PVPR9xzT80kQxdZeJ+zduCB3uj0="; pin-sha256="LvRiGEjRqfzurezaWuj8Wie2gyHMrW5Q06LspMnox7A="; includeSubDomains