ストーリー
高橋アーキテクトがネットワーク図を広げました。
TLS(Transport Layer Security)
TLSは、通信を暗号化して盗聴・改ざんを防ぐプロトコルです。
TLSハンドシェイクの流れ
sequenceDiagram
participant C as クライアント
participant S as サーバー
C->>S: ClientHello(対応する暗号スイート一覧)
S->>C: ServerHello(選択した暗号スイート + 証明書)
C->>S: 鍵交換(プリマスターシークレット)
Note over C,S: 共通鍵で暗号化通信開始
TLS設定のベストプラクティス
import https from "https";
import fs from "fs";
const server = https.createServer(
{
// 証明書の設定
key: fs.readFileSync("/etc/ssl/private/server.key"),
cert: fs.readFileSync("/etc/ssl/certs/server.crt"),
ca: fs.readFileSync("/etc/ssl/certs/ca.crt"),
// TLS 1.2以上のみ許可
minVersion: "TLSv1.2",
// 安全な暗号スイートのみ使用
ciphers: [
"TLS_AES_256_GCM_SHA384",
"TLS_CHACHA20_POLY1305_SHA256",
"TLS_AES_128_GCM_SHA256",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
].join(":"),
// サーバーの暗号スイート優先順位を使用
honorCipherOrder: true,
},
app,
);
// HTTP → HTTPS リダイレクト
import http from "http";
http.createServer((req, res) => {
res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
res.end();
}).listen(80);
mTLS(mutual TLS)
mTLSは、サーバーだけでなくクライアントも証明書で認証する方式です。マイクロサービス間通信のゼロトラストに不可欠です。
// mTLSサーバーの設定
const mtlsServer = https.createServer(
{
key: fs.readFileSync("/etc/ssl/private/server.key"),
cert: fs.readFileSync("/etc/ssl/certs/server.crt"),
ca: fs.readFileSync("/etc/ssl/certs/ca.crt"),
// クライアント証明書を要求
requestCert: true,
// クライアント証明書の検証を強制
rejectUnauthorized: true,
},
(req, res) => {
// クライアント証明書の情報を取得
const clientCert = req.socket.getPeerCertificate();
const clientService = clientCert.subject.CN; // Common Name
console.log(`Authenticated service: ${clientService}`);
// サービス名に基づいて認可チェック
},
);
// mTLSクライアントの設定
import axios from "axios";
const mtlsClient = axios.create({
httpsAgent: new https.Agent({
cert: fs.readFileSync("/etc/ssl/certs/client.crt"),
key: fs.readFileSync("/etc/ssl/private/client.key"),
ca: fs.readFileSync("/etc/ssl/certs/ca.crt"),
}),
});
// サービス間通信
const response = await mtlsClient.get("https://internal-service:8443/api/data");
証明書管理
証明書のライフサイクル
| フェーズ | 説明 | 自動化 |
|---|---|---|
| 発行 | CA から証明書を取得 | Let’s Encrypt + certbot |
| 配布 | サーバーに証明書を配置 | cert-manager (K8s) |
| 監視 | 有効期限を監視 | アラート設定 |
| 更新 | 有効期限前に自動更新 | 自動更新スクリプト |
| 失効 | 侵害時に証明書を無効化 | CRL / OCSP |
// 証明書の有効期限監視
import tls from "tls";
const checkCertExpiry = async (hostname: string, port: number = 443) => {
return new Promise<{ daysRemaining: number; expiryDate: Date }>((resolve, reject) => {
const socket = tls.connect(port, hostname, { servername: hostname }, () => {
const cert = socket.getPeerCertificate();
const expiryDate = new Date(cert.valid_to);
const now = new Date();
const daysRemaining = Math.floor(
(expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24),
);
socket.end();
resolve({ daysRemaining, expiryDate });
});
socket.on("error", reject);
});
};
// 定期的な証明書チェック
const monitorCertificates = async () => {
const hosts = ["api.example.com", "auth.example.com", "db.example.com"];
for (const host of hosts) {
const { daysRemaining, expiryDate } = await checkCertExpiry(host);
if (daysRemaining < 30) {
await sendAlert({
severity: daysRemaining < 7 ? "critical" : "warning",
message: `Certificate for ${host} expires in ${daysRemaining} days (${expiryDate.toISOString()})`,
});
}
}
};
セキュリティヘッダー
通信の保護にはHTTPセキュリティヘッダーも重要です。
import helmet from "helmet";
app.use(helmet());
// 個別のヘッダー設定
app.use(helmet.hsts({
maxAge: 31536000, // 1年間HTTPS強制
includeSubDomains: true,
preload: true,
}));
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"], // 外部スクリプト禁止
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
connectSrc: ["'self'", "https://api.example.com"],
frameSrc: ["'none'"], // iframe禁止
objectSrc: ["'none'"],
},
}));
// 追加のセキュリティヘッダー
app.use((req, res, next) => {
res.setHeader("X-Content-Type-Options", "nosniff");
res.setHeader("X-Frame-Options", "DENY");
res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
res.setHeader("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
next();
});
通信保護の全体像
| 経路 | 保護方式 |
|---|---|
| ブラウザ → API | TLS 1.2+ (HTTPS) |
| API → API(内部) | mTLS |
| API → データベース | TLS + 認証 |
| API → 外部サービス | TLS + APIキー |
| CI/CD → 本番 | mTLS + VPN |
まとめ
| ポイント | 内容 |
|---|---|
| TLS | 通信の暗号化、TLS 1.2以上を使用 |
| mTLS | クライアントも証明書で認証、サービス間通信に必須 |
| 証明書管理 | 自動更新と有効期限監視が重要 |
| セキュリティヘッダー | HSTS, CSP 等でブラウザの防御を強化 |
チェックリスト
- TLSハンドシェイクの流れを理解した
- mTLSの仕組みと用途を把握した
- 証明書のライフサイクル管理を理解した
- セキュリティヘッダーの設定方法を把握した
次のステップへ
次は演習です。ここまで学んだデータ保護の知識を使って、包括的なデータ保護設計を行いましょう。
推定読了時間: 40分