Skip to content

HTTPS

[Стабильно: 2 - Стабильно]

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

Исходный код: lib/https.js

HTTPS — это протокол HTTP поверх TLS/SSL. В Node.js он реализован как отдельный модуль.

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

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

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

js
let https
try {
  https = require('node:https')
} catch (err) {
  console.error('Поддержка https отключена!')
}

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

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

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

Класс: https.Agent

[История]

ВерсияИзменения
v5.3.0Поддержка 0 maxCachedSessions для отключения кэширования сеансов TLS.
v2.5.0Параметр maxCachedSessions добавлен в options для повторного использования сеансов TLS.
v0.4.5Добавлено в: v0.4.5

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

new Agent([options])

[История]

ВерсияИзменения
v12.5.0Не устанавливать автоматически имя сервера, если целевой хост был указан с использованием IP-адреса.
  • options <Объект> Набор настраиваемых параметров для установки в агенте. Может иметь те же поля, что и для http.Agent(options), а также
    • maxCachedSessions <число> максимальное количество кэшированных сеансов TLS. Используйте 0, чтобы отключить кэширование сеансов TLS. По умолчанию: 100.
    • servername <строка> значение расширения Server Name Indication, которое будет отправлено на сервер. Используйте пустую строку '', чтобы отключить отправку расширения. По умолчанию: имя хоста целевого сервера, если только целевой сервер не указан с использованием IP-адреса, в этом случае значение по умолчанию — '' (расширение не отправляется). См. Возобновление сеанса для получения информации о повторном использовании сеансов TLS.

Событие: 'keylog'

Добавлено в: v13.2.0, v12.16.0

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

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

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

js
// ...
https.globalAgent.on('keylog', (line, tlsSocket) => {
  fs.appendFileSync('/tmp/ssl-keys.log', line, { mode: 0o600 })
})

Класс: https.Server

Добавлено в: v0.3.4

См. http.Server для получения дополнительной информации.

server.close([callback])

Добавлено в: v0.1.90

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

server[Symbol.asyncDispose]()

Добавлено в: v20.4.0

[Стабильно: 1 - Экспериментально]

Стабильно: 1 Стабильность: 1 - Экспериментально

Вызывает server.close() и возвращает promise, который выполняется после закрытия сервера.

server.closeAllConnections()

Добавлено в: v18.2.0

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

server.closeIdleConnections()

Добавлено в: v18.2.0

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

server.headersTimeout

Добавлен в: v11.3.0

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

server.listen()

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

server.maxHeadersCount

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

server.requestTimeout

[История]

ВерсияИзменения
v18.0.0Время ожидания запроса по умолчанию изменено с неограниченного на 300 с (5 минут).
v14.11.0Добавлено в: v14.11.0

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

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

Добавлен в: v0.11.2

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

server.timeout

[История]

ВерсияИзменения
v13.0.0Время ожидания по умолчанию изменено с 120 с на 0 (неограниченное время ожидания).
v0.11.2Добавлено в: v0.11.2
  • <число> По умолчанию: 0 (неограниченное время ожидания)

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

server.keepAliveTimeout

Добавлено в: v8.0.0

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

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

Добавлено в: v0.3.4

js
// curl -k https://localhost:8000/
import { createServer } from 'node:https'
import { readFileSync } from 'node:fs'

const options = {
  key: readFileSync('private-key.pem'),
  cert: readFileSync('certificate.pem'),
}

createServer(options, (req, res) => {
  res.writeHead(200)
  res.end('hello world\n')
}).listen(8000)
js
// curl -k https://localhost:8000/
const https = require('node:https')
const fs = require('node:fs')

const options = {
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
}

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

Или

js
import { createServer } from 'node:https'
import { readFileSync } from 'node:fs'

const options = {
  pfx: readFileSync('test_cert.pfx'),
  passphrase: 'sample',
}

createServer(options, (req, res) => {
  res.writeHead(200)
  res.end('hello world\n')
}).listen(8000)
js
const https = require('node:https')
const fs = require('node:fs')

const options = {
  pfx: fs.readFileSync('test_cert.pfx'),
  passphrase: 'sample',
}

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

Для генерации сертификата и ключа для этого примера выполните:

bash
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' \
  -keyout private-key.pem -out certificate.pem

Затем, для генерации сертификата pfx для этого примера выполните:

bash
openssl pkcs12 -certpbe AES-256-CBC -export -out test_cert.pfx \
  -inkey private-key.pem -in certificate.pem -passout pass:sample

https.get(options[, callback])

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

[История]

ВерсияИзменения
v10.9.0Теперь параметр url может передаваться вместе с отдельным объектом options.
v7.5.0Параметр options может быть объектом WHATWG URL.
v0.3.6Добавлено в: v0.3.6

Аналогично http.get(), но для HTTPS.

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

js
import { get } from 'node:https'
import process from 'node:process'

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)
})
js
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

[История]

ВерсияИзменения
v19.0.0Агент теперь использует HTTP Keep-Alive и таймаут 5 секунд по умолчанию.
v0.5.9Добавлено в: v0.5.9

Глобальный экземпляр https.Agent для всех HTTPS-запросов клиента. Отличается от конфигурации по умолчанию https.Agent включенным keepAlive и таймаутом в 5 секунд.

https.request(options[, callback])

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

[История]

ВерсияИзменения
v22.4.0, v20.16.0Опция clientCertEngine зависит от поддержки пользовательского движка в OpenSSL, которая устарела в OpenSSL 3.
v16.7.0, v14.18.0При использовании объекта URL имя пользователя и пароль теперь будут правильно декодированы URI.
v14.1.0, v13.14.0Теперь принимается опция highWaterMark.
v10.9.0Теперь параметр url может передаваться вместе с отдельным объектом options.
v9.3.0Параметр options теперь может включать clientCertEngine.
v7.5.0Параметр options может быть объектом WHATWG URL.
v0.3.6Добавлено в: v0.3.6

Выполняет запрос к защищенному веб-серверу.

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

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

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

js
import { request } from 'node:https'
import process from 'node:process'

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

const req = 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()
js
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():

js
const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
}
options.agent = new https.Agent(options)

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

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

js
const options = {
  hostname: 'encrypted.google.com',
  port: 443,
  path: '/',
  method: 'GET',
  key: fs.readFileSync('private-key.pem'),
  cert: fs.readFileSync('certificate.pem'),
  agent: false,
}

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

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

js
const options = new URL('https://abc:')

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

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

js
import { checkServerIdentity } from 'node:tls'
import { Agent, request } from 'node:https'
import { createHash } from 'node:crypto'

function sha256(s) {
  return createHash('sha256').update(s).digest('base64')
}
const options = {
  hostname: 'github.com',
  port: 443,
  path: '/',
  method: 'GET',
  checkServerIdentity: function (host, cert) {
    // Убедитесь, что сертификат выдан для хоста, к которому мы подключены
    const err = checkServerIdentity(host, cert)
    if (err) {
      return err
    }

    // Прикрепите открытый ключ, аналогично прикреплению HPKP pin-sha256
    const pubkey256 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8='
    if (sha256(cert.pubkey) !== pubkey256) {
      const msg =
        'Ошибка проверки сертификата: ' +
        `Открытый ключ '${cert.subject.CN}' ` +
        'не соответствует нашему прикрепленному отпечатку'
      return new Error(msg)
    }

    // Прикрепите точный сертификат, а не открытый ключ
    const cert256 =
      'FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:' + '0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65'
    if (cert.fingerprint256 !== cert256) {
      const msg =
        'Ошибка проверки сертификата: ' +
        `Сертификат '${cert.subject.CN}' ` +
        'не соответствует нашему прикрепленному отпечатку'
      return new Error(msg)
    }

    // Этот цикл служит только для информационных целей.
    // Выведите отпечатки сертификата и открытого ключа всех сертификатов в
    // цепочке. Обычно открытый ключ эмитента прикрепляется в публичном
    // интернете, а открытый ключ службы — в чувствительных
    // средах.
    let lastprint256
    do {
      console.log('Общее имя субъекта:', cert.subject.CN)
      console.log('  Отпечаток SHA256 сертификата:', cert.fingerprint256)

      const hash = createHash('sha256')
      console.log('  Прикрепление открытого ключа ping-sha256:', sha256(cert.pubkey))

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

options.agent = new Agent(options)
const req = request(options, res => {
  console.log('Все ОК. Сервер соответствует нашему прикрепленному сертификату или открытому ключу')
  console.log('statusCode:', res.statusCode)

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

req.on('error', e => {
  console.error(e.message)
})
req.end()
js
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) {
    // Убедитесь, что сертификат выдан для хоста, к которому мы подключены
    const err = tls.checkServerIdentity(host, cert)
    if (err) {
      return err
    }

    // Прикрепите открытый ключ, аналогично прикреплению HPKP pin-sha256
    const pubkey256 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8='
    if (sha256(cert.pubkey) !== pubkey256) {
      const msg =
        'Ошибка проверки сертификата: ' +
        `Открытый ключ '${cert.subject.CN}' ` +
        'не соответствует нашему прикрепленному отпечатку'
      return new Error(msg)
    }

    // Прикрепите точный сертификат, а не открытый ключ
    const cert256 =
      'FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:' + '0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65'
    if (cert.fingerprint256 !== cert256) {
      const msg =
        'Ошибка проверки сертификата: ' +
        `Сертификат '${cert.subject.CN}' ` +
        'не соответствует нашему прикрепленному отпечатку'
      return new Error(msg)
    }

    // Этот цикл служит только для информационных целей.
    // Выведите отпечатки сертификата и открытого ключа всех сертификатов в
    // цепочке. Обычно открытый ключ эмитента прикрепляется в публичном
    // интернете, а открытый ключ службы — в чувствительных
    // средах.
    do {
      console.log('Общее имя субъекта:', cert.subject.CN)
      console.log('  Отпечаток SHA256 сертификата:', cert.fingerprint256)

      hash = crypto.createHash('sha256')
      console.log('  Прикрепление открытого ключа 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('Все ОК. Сервер соответствует нашему прикрепленному сертификату или открытому ключу')
  console.log('statusCode:', res.statusCode)

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

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

Вывод примера:

text
Общее имя субъекта: github.com
  Отпечаток SHA256 сертификата: FD:6E:9B:0E:F3:98:BC:D9:04:C3:B2:EC:16:7A:7B:0F:DA:72:01:C9:03:C5:3A:6A:6A:E5:D0:41:43:63:EF:65
  Прикрепление открытого ключа ping-sha256: SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=
Общее имя субъекта: Sectigo ECC Domain Validation Secure Server CA
  Отпечаток SHA256 сертификата: 61:E9:73:75:E9:F6:DA:98:2F:F5:C1:9E:2F:94:E6:6C:4E:35:B6:83:7C:E3:B9:14:D2:24:5C:7F:5F:65:82:5F
  Прикрепление открытого ключа ping-sha256: Eep0p/AsSa9lFUH6KT2UY+9s1Z8v7voAPkQ4fGknZ2g=
Общее имя субъекта: USERTrust ECC Certification Authority
  Отпечаток SHA256 сертификата: A6:CF:64:DB:B4:C8:D5:FD:19:CE:48:89:60:68:DB:03:B5:33:A8:D1:33:6C:62:56:A8:7D:00:CB:B3:DE:F3:EA
  Прикрепление открытого ключа ping-sha256: UJM2FOhG9aTNY0Pg4hgqjNzZ/lQBiMGRxPD5Y2/e0bw=
Общее имя субъекта: AAA Certificate Services
  Отпечаток SHA256 сертификата: D7:A7:A0:FB:5D:7E:27:31:D7:71:E9:48:4E:BC:DE:F7:1D:5F:0C:3E:0A:29:48:78:2B:C8:3E:E0:EA:69:9E:F4
  Прикрепление открытого ключа ping-sha256: vRU+17BDT2iGsXvOi76E7TQMcTLXAqj0+jGPdW7L1vM=
Все ОК. Сервер соответствует нашему прикрепленному сертификату или открытому ключу
statusCode: 200