HTTPS#

安定性: 2 - Stable

ソースコード: lib/https.js

HTTPSはTLS/SSL上のHTTPプロトコルです。Node.jsでは、これは独立したモジュールとして実装されています。

暗号化サポートが利用不可かどうかの判断#

Node.jsは、node:cryptoモジュールのサポートを含まずにビルドされることがあります。そのような場合、httpsからimportしようとしたり、require('node:https')を呼び出したりすると、エラーがスローされます。

CommonJSを使用している場合、スローされたエラーはtry/catchを使ってキャッチできます。

let https;
try {
  https = require('node:https');
} catch (err) {
  console.error('https support is disabled!');
} 

レキシカルなESMのimportキーワードを使用する場合、モジュールをロードしようとするに(例えば、プリロードモジュールを使用して)process.on('uncaughtException')のハンドラーが登録されている場合にのみエラーをキャッチできます。

ESMを使用している場合、暗号化サポートが有効になっていないNode.jsのビルドでコードが実行される可能性があるなら、レキシカルなimportキーワードの代わりにimport()関数の使用を検討してください。

let https;
try {
  https = await import('node:https');
} catch (err) {
  console.error('https support is disabled!');
} 

クラス: https.Agent#

http.Agentに似た、HTTPS用のAgentオブジェクトです。詳しくはhttps.request()を参照してください。

new Agent([options])#

  • options <Object> エージェントに設定する構成可能なオプションのセット。http.Agent(options)と同じフィールドを持つことができ、さらに以下を持ちます。
    • maxCachedSessions <number> キャッシュされるTLSセッションの最大数。TLSセッションキャッシュを無効にするには0を使用します。デフォルト: 100

    • servername <string> サーバーに送信されるServer Name Indication拡張の値。拡張の送信を無効にするには空文字列''を使用します。デフォルト: ターゲットサーバーのホスト名。ただし、ターゲットサーバーがIPアドレスで指定されている場合は、デフォルトは''(拡張なし)になります。

      TLSセッションの再利用に関する情報については、セッション再開を参照してください。

イベント: 'keylog'#
  • line <Buffer> NSS SSLKEYLOGFILE形式のASCIIテキストの行。
  • tlsSocket <tls.TLSSocket> それが生成されたtls.TLSSocketインスタンス。

keylogイベントは、このエージェントによって管理される接続で鍵素材が生成または受信されたとき(通常はハンドシェイクが完了する前ですが、必ずしもそうではありません)に発生します。この鍵素材は、キャプチャされたTLSトラフィックの復号を可能にするため、デバッグ用に保存できます。ソケットごとに複数回発生することがあります。

典型的なユースケースは、受信した行を共通のテキストファイルに追加し、後でそのファイルを(Wiresharkなどの)ソフトウェアがトラフィックの復号に使用することです。

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

クラス: https.Server#

詳しくはhttp.Serverを参照してください。

server.close([callback])#

node:httpモジュールのserver.close()を参照してください。

server[Symbol.asyncDispose]()#

server.close()を呼び出し、サーバーがクローズしたときに解決されるpromiseを返します。

server.closeAllConnections()#

node:httpモジュールのserver.closeAllConnections()を参照してください。

server.closeIdleConnections()#

node:httpモジュールのserver.closeIdleConnections()を参照してください。

server.headersTimeout#

node:httpモジュールのserver.headersTimeoutを参照してください。

server.listen()#

HTTPSサーバーが暗号化された接続を待ち受けるのを開始します。このメソッドはnet.Serverserver.listen()と同じです。

server.maxHeadersCount#

node:httpモジュールのserver.maxHeadersCountを参照してください。

server.requestTimeout#

node:httpモジュールのserver.requestTimeoutを参照してください。

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

node:httpモジュールのserver.setTimeout()を参照してください。

server.timeout#

  • 型: <number> デフォルト: 0 (タイムアウトなし)

node:httpモジュールのserver.timeoutを参照してください。

server.keepAliveTimeout#

  • 型: <number> デフォルト: 5000 (5秒)

node:httpモジュールのserver.keepAliveTimeoutを参照してください。

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

// curl -k https://: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);// curl -k https://: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);

または

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);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);

この例の証明書と鍵を生成するには、以下を実行します。

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

次に、この例のpfx証明書を生成するには、以下を実行します。

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])#

http.get()と同様ですが、HTTPS用です。

optionsはオブジェクト、文字列、またはURLオブジェクトにすることができます。optionsが文字列の場合、new URL()で自動的にパースされます。URLオブジェクトの場合、自動的に通常のoptionsオブジェクトに変換されます。

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);
});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クライアントリクエストのためのhttps.Agentのグローバルインスタンス。keepAliveが有効で、timeoutが5秒である点で、デフォルトのhttps.Agent設定とは異なります。

https.request(options[, callback])#

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

セキュアなWebサーバーにリクエストを送信します。

tls.connect()からの以下の追加のoptionsも受け付けられます: 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オブジェクトに書き込みます。

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();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()のオプションを使用した例

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を使用しないことで、コネクションプーリングをオプトアウトします。

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) => {
  // ...
}); 

optionsとしてURLを使用した例

const options = new URL('https://abc:xyz@example.com');

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

証明書のフィンガープリント、または公開鍵にピニングする例(pin-sha256に類似)

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) {
    // Make sure the certificate is issued to the host we are connected to
    const err = checkServerIdentity(host, cert);
    if (err) {
      return err;
    }

    // Pin the public key, similar to HPKP pin-sha256 pinning
    const pubkey256 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=';
    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 = '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 = '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.
    let lastprint256;
    do {
      console.log('Subject Common Name:', cert.subject.CN);
      console.log('  Certificate SHA256 fingerprint:', cert.fingerprint256);

      const hash = createHash('sha256');
      console.log('  Public key 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('All OK. Server matched our pinned cert or public key');
  console.log('statusCode:', res.statusCode);

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

req.on('error', (e) => {
  console.error(e.message);
});
req.end();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 = 'SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=';
    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 = '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 = '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);

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

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

例えば、以下の出力

Subject Common Name: github.com
  Certificate SHA256 fingerprint: 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
  Public key ping-sha256: SIXvRyDmBJSgatgTQRGbInBaAK+hZOQ18UmrSwnDlK8=
Subject Common Name: Sectigo ECC Domain Validation Secure Server CA
  Certificate SHA256 fingerprint: 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
  Public key ping-sha256: Eep0p/AsSa9lFUH6KT2UY+9s1Z8v7voAPkQ4fGknZ2g=
Subject Common Name: USERTrust ECC Certification Authority
  Certificate SHA256 fingerprint: 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
  Public key ping-sha256: UJM2FOhG9aTNY0Pg4hgqjNzZ/lQBiMGRxPD5Y2/e0bw=
Subject Common Name: AAA Certificate Services
  Certificate SHA256 fingerprint: 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
  Public key ping-sha256: vRU+17BDT2iGsXvOi76E7TQMcTLXAqj0+jGPdW7L1vM=
All OK. Server matched our pinned cert or public key
statusCode: 200