2026年10月8日にIETFのTLS 1.3(RFC 8446)とHTTP Semantics(RFC 9110)、MDNのHTTP概要を本文まで再確認した。TLSは通信路の機密性・完全性・相手の証明書検証を支えるが、アプリケーションの認証・認可や入力検証を代替しない。TLS 1.3のハンドシェイク、バージョン交渉、ダウングレード対策を確認し、0-RTTは再送・リプレイを許容できる操作に限るという運用判断まで分けて考える。HTTPS化だけで安全性や可用性を保証したとは扱わない。
HTTPSで接続すると、ブラウザと通信相手の間でやり取りする内容を保護できます。ただし、その相手から先の通信や、保存されたデータ、ログイン後の権限まで同じ仕組みで守れるわけではありません。
この記事では、SSLと後継のTLS、証明書、通信が保護される範囲を説明し、HTTPSクライアント、Nginx、Node.jsサーバーの三つの教材で役割を確かめます。
30秒で要点
- 現在のHTTPSで使うTLSは、通信の暗号化、改ざんの検知、接続先の確認を担います。「SSL」という商品名だけで使用する方式は分かりません。
- 証明書は、信頼する発行元、接続するホスト名、有効期限などを検証して使います。検証を無効にして警告を消さないようにします。
- ブラウザから中継サーバー、中継サーバーからアプリという経路は別に確認します。通信の保護と、アプリの認可・保存情報の保護を分けます。
SSLという呼び名と、実際のTLS通信
SSLはTLSより前に使われていたプロトコルです。「SSL証明書」「SSL化」という呼び名が残っていても、実際の通信ではTLSの設定を確認します。
RFC9325は、TLS1.0と1.1を使わないこと、TLS1.2をサポートすること、TLS1.3のサポートと優先を勧めることなどを示しています。古い方式を残せばすべての利用者に安全に対応できる、という関係ではありません。利用するサーバーとライブラリの対応を確認します。表が収まらない場合は、横にスクロールできます
| TLSで扱うこと | 内容 | それだけでは分からないこと |
|---|---|---|
| 暗号化 | 通信内容を第三者に読まれにくくする | 保存後のデータが暗号化されているか |
| 完全性 | 通信の変更を検知する | 元の情報や広告が正しいか |
| 接続先の確認 | 証明書などを使って相手を検証する | 運営者の商品や業務が信用できるか |
一般的なWebの接続ではサーバーの証明書を確認します。利用者本人のログインは別の仕組みです。認証と認可は、TLSとは別の層で扱います。
証明書で何を確認するのか
証明書には公開鍵や対象となる名前などの情報が含まれます。接続時には、信頼する認証局につながるか、接続先のホスト名に合うか、期限などの条件を満たすかを確認します。
ドメイン名が似ている別サイトの証明書が正しくても、自分が意図した相手であるとは限りません。また、証明書があるだけで、サイト内に保存する個人情報や管理画面の権限が安全だとは判断できません。
自己署名証明書も、誰が何を信頼するかを明示的に管理した検証には使えます。問題は信頼の確認を省くことです。Node.jsでrejectUnauthorized: falseにするなど、証明書検証を無効にして動いたことを成功条件にしないようにします。Node.js TLSの説明で、証明書とホスト名の検証条件を確認できます。
接続開始時に、鍵と通信条件を整える
TLSの接続開始時にはハンドシェイクという手続きを行います。一般的な証明書を使う接続では、対応する条件を確かめ、サーバーの証明書を検証し、通信に使う鍵を確立します。手順や選べる方式はバージョンによって異なります。
TLS1.3の仕様では、特定の再接続で早期にデータを送る仕組みも扱います。ただし0-RTTと呼ばれる早期データには再送攻撃に関する留保があります。購入や送金などの操作を、速くなるという理由だけで無条件に載せる判断にはしません。TLSが終わる場所から、次の経路を確認する
中継サーバーやCDNでHTTPSを受け、そこで復号してアプリへ渡す構成があります。この地点をTLSの終端と呼びます。
たとえば、ブラウザからNginxまではTLS、Nginxから同じホストのアプリまではHTTPという構成では、保護する範囲が違います。後半を別ホストへ伸ばす場合に、同じ設定のままでよいとは限りません。中継から先にもTLSを使うなら、そこでの接続先と証明書検証も確認します。
HTTPSクライアントの教材
次のclient.cjsは、後述のローカルサーバーへGETを送る構成です。事前に、この検証専用のlocalhostに有効な証明書と鍵を用意します。証明書はlocalhostの名前を含み、local-ca.pemは発行元として信頼する検証用CA証明書です。証明書の発行手順や信頼設定は利用環境に合わせて別途用意する必要があります。
const https = require('node:https');
const fs = require('node:fs');
const req = https.request({
hostname: 'localhost',
port: 8443,
path: '/',
method: 'GET',
ca: fs.readFileSync('local-ca.pem'),
minVersion: 'TLSv1.2',
}, (res) => {
console.log('statusCode:', res.statusCode);
res.setEncoding('utf8');
res.on('data', (chunk) => process.stdout.write(chunk));
res.on('error', (error) => {
console.error(error.code || error.message || 'HTTPS request failed');
process.exitCode = 1;
});
});
req.setTimeout(5000, () => req.destroy(new Error('Request timed out')));
req.on('error', (error) => {
console.error(error.code || error.message || 'HTTPS request failed');
process.exitCode = 1;
});
req.end();
証明書が正しくても、接続名が証明書の対象と違えば検証に失敗する場合があります。「暗号化して接続できること」と「意図した接続先を検証できること」を一緒に確認します。ここで設定するタイムアウトは、接続後のソケットの無通信を検出する教材条件です。Node.jsの説明どおり、通知だけでは要求を中止しないためdestroyを呼んでいます。処理全体を必ず5秒以内に終える上限ではなく、どのサービスにも適した値とは限りません。
NginxでTLSを終える教材
次はhttpコンテキストの中に置くserverブロックの例です。NginxのTLSモジュールと対応するライブラリ、実際の証明書・秘密鍵、同じホストの127.0.0.1:8080で動くアプリが前提になります。パスやドメインは説明用で、配置するだけで起動できる完成済み環境ではありません。
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/tls/fullchain.pem;
ssl_certificate_key /etc/nginx/tls/private-key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
この例はNginxからアプリへの区間がHTTPであることを意図的に示しています。外部のホストへそのまま転用しません。アプリが転送されたヘッダーを使う場合も、どの中継を信頼するかを別に設定します。
NginxのTLSモジュール説明には証明書、鍵、プロトコルの指定があります。転送先とヘッダー指定はproxyモジュールの説明に対応します。公式ページ上の古い暗号方式を含む例まで一括で複製せず、導入する版と環境で必要な設定を確認します。公開用の秘密鍵はリポジトリやログへ保存しません。Node.jsでTLSを終える教材
次のserver.cjsは、Nginxを使わずNode.js自身がTLSを扱う別の構成です。localhost.pemとlocalhost-key.pemは、この検証用に用意した証明書と秘密鍵です。クライアントと同じ作業ディレクトリで用いる想定で、node server.cjsを実行してから別の端末でnode client.cjsを実行する手順になります。
const https = require('node:https');
const fs = require('node:fs');
const server = https.createServer({
key: fs.readFileSync('localhost-key.pem'),
cert: fs.readFileSync('localhost.pem'),
minVersion: 'TLSv1.2',
}, (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Local TLS learning example\n');
});
server.on('error', (error) => {
console.error(error.code || error.message || 'HTTPS request failed');
process.exitCode = 1;
});
server.listen(8443, 'localhost', () => {
console.log('Listening on https://localhost:8443');
});
Node.js HTTPS APIを使い、このサーバーはテキストを返すための教材です。ログイン、認可、リクエスト制限、証明書更新、監視を含む本番用サーバーの完成例ではありません。停止は起動した端末から行い、検証用の秘密鍵も適切に管理します。
正常な接続と、拒否される接続を確かめる
最小の確認では、正しい名前と信頼設定の接続が成功することに加え、信頼するCAが違う場合や接続名が合わない場合に失敗することを確認します。失敗を消すために検証を無効化せず、証明書、名前、信頼のどれが異なるかを調べます。
運用時には、証明書の期限と更新担当、更新後に実際に配られる証明書、中継から先の経路を確認します。これらが整っていても、アプリの権限確認や保存データの保護は別の課題として残ります。TLSで守る区間を図に描き、区間ごとに誰が設定と更新を担うかを説明できることが、最初の判断材料になります。