説明
rejectUnauthorized: false や NODE_TLS_REJECT_UNAUTHORIZED=0 などでサーバー証明書の検証を無効にすると、TLS クライアントがサーバーの身元を適切に確認できなくなります。通信経路上の攻撃者が信頼されていない証明書を提示し、正規のサーバーになりすます可能性があります。悪意のあるプロキシ、ゲートウェイ、公衆ネットワークなどを介した傍受により、機密情報の漏えい、応答の改ざん、セッションの窃取につながるおそれがあります。
想定される影響
- 中間者が偽の証明書を使って接続を成立させる可能性があります。
- 認証情報、トークン、個人情報などが、サーバーになりすました攻撃者に漏れるおそれがあります。TLS の暗号化自体がなくなるわけではありません。
- 応答の書き換えや悪意のあるペイロードの挿入が行われる可能性があります。
- 正規のサービスだと誤認したまま、攻撃者と通信するおそれがあります。
対処方法
rejectUnauthorizedを削除するか、既定のtrueを維持してください。process.env.NODE_TLS_REJECT_UNAUTHORIZED=0で検証を全体的に無効にしないでください。- 社内または公開 CA の信頼する証明書を、
https.Agentやtls.connectのcaで指定してください。 - ホスト名検証を有効にしてください。
tls.connectは SNI を自動で有効にしないため、サーバーに必要な場合はhostと併せてservernameを設定してください。 - ピンニングが必要な場合は、信頼する証明書や公開キーとの一致を確認し、証明書の更新にも備えてください。以下の
fingerprint256は、公開キーではなく証明書全体の SHA-256 フィンガープリントを比較します。 - テスト用に一時的な例外が必要な場合は、本番の設定やビルドから分離してください。
例
変更前
javascript
// 変更前の例 1: 証明書検証を全体で無効化
const https = require('https');
const tls = require('tls');
function fetchInsecure() {
// TLS 検証の全体的な無効化は危険
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
https.get({ hostname: 'api.example.org', path: '/v1/data' }, (res) => {
res.on('data', () => {});
});
}
// 変更前の例 2: エージェントで証明書検証を無効化
function postInsecure() {
const insecureAgent = new https.Agent({ keepAlive: true, rejectUnauthorized: false });
const req = https.request({
hostname: 'secure.example.org',
method: 'POST',
path: '/login',
agent: insecureAgent,
headers: { 'Content-Type': 'application/json' }
}, (res) => res.resume());
req.write(JSON.stringify({ user: 'alice', pass: 'secret' }));
req.end();
}
変更後
javascript
// 変更後: 既定の検証を維持し、信頼する CA バンドルを使用
const https = require('https');
const fs = require('fs');
// 社内または公開 CA バンドルのパスの例
const caBundle = fs.readFileSync('/etc/ssl/certs/company-ca-bundle.pem');
function fetchSecure() {
// rejectUnauthorized の既定値は true
const secureAgent = new https.Agent({
keepAlive: true,
ca: caBundle, // 信頼する CA を指定
// https は要求先ホストから servername を設定するため、無効にしない
});
https.get({
hostname: 'api.example.org',
path: '/v1/data',
agent: secureAgent
}, (res) => {
let body = '';
res.on('data', (c) => body += c);
res.on('end', () => console.log('OK:', body.length));
});
}
// 必要に応じた証明書ピンニング: 証明書の SHA-256 フィンガープリントを比較
const tls = require('tls');
function connectWithPinning(expectedFingerprint256) {
const socket = tls.connect({ host: 'secure.example.org', port: 443, ca: caBundle }, () => {
const cert = socket.getPeerCertificate(true);
if (!cert || !cert.fingerprint256 || cert.fingerprint256 !== expectedFingerprint256) {
socket.destroy(new Error('Certificate pinning mismatch'));
return;
}
socket.write('GET / HTTP/1.1\r\nHost: secure.example.org\r\n\r\n');
});
}
説明:
- 変更前:
rejectUnauthorized: falseやNODE_TLS_REJECT_UNAUTHORIZED=0により、証明書やホスト名の検証に失敗しても接続できるため、偽の証明書を使ったなりすましを許すおそれがあります。 - 変更後: 既定の検証(
rejectUnauthorized: true)と信頼する CA バンドルでサーバーを認証します。必要に応じたピンニングは追加の確認になります。本番環境では CA の信頼設定、ホスト名検証、証明書更新時の動作も確認してください。