株式会社シンシアでは、実務未経験のエンジニアの方や学生エンジニアインターンを採用し一緒に働いています。
※ シンシアにおける働き方の様子はこちら
シンシアでは、年間100人程度の実務未経験の方が応募し技術面接を受けます。
その経験を通し、実務未経験者の方にぜひ身につけて欲しい技術力(文法)をここでは紹介していきます。
はじめに
HTTPS通信は、Webの安全性を支える重要な技術です。本記事では、HTTPS・TLS・鍵交換・証明書認証の仕組みを、初心者でも理解しやすい流れで整理します。
この記事を書いた背景
会社でミニアプリケーションを開発し、ConoHaのVPSサーバーにデプロイして運用していたときのことです。
アプリは正常に動作しており、HTTPSでアクセスできる状態でした。しかし、ある日突然証明書エラーが発生し、クライアントアプリに「ssl_cacert」という警告が表示されるようになりました。
調査してみると、Let's Encryptで取得した証明書の有効期限が切れていたことが原因でした。Let's Encryptの証明書は90日間の有効期限があり、自動更新の設定をしていなかったため、気づかないうちに期限切れになっていたのです。
この経験から、以下のような疑問が湧いてきました:
- そもそもHTTPSってどういう仕組みなの?
- 証明書は何のために必要なの?
- Let's Encryptはどうやってドメイン所有を確認しているの?
- 暗号化通信はどうやって実現されているの?
これらの疑問を解決するために調べた内容を、本記事でまとめています。同じような経験をした方や、HTTPS通信の仕組みを理解したい方の参考になれば幸いです。
証明書エラーをどう解決したか
実際に発生した証明書の有効期限切れ問題は、以下の手順で解決しました。
1. 証明書の状態を確認
まず、curlコマンドで証明書の状態を確認しました。
curl -v https://slack-bot.xincere.jp
実行結果に「certificate has expired」というエラーメッセージが表示され、証明書が期限切れであることが判明しました。
2. Let's Encrypt証明書を更新
証明書を更新するために、以下のコマンドを実行しました。
# Nginxを一時停止(ポート80/443を開放)
systemctl stop nginx
# 証明書を更新
certbot renew
# Nginxを再起動
systemctl start nginx
certbot renewコマンドは、期限切れまたは期限切れ間近の証明書を自動的に更新してくれます。
3. 更新後の検証
証明書の更新が成功したか、再度curlで確認しました。
curl -v https://slack-bot.sample.jp
今度は「SSL certificate verify ok」と表示され、証明書が正常に更新されたことを確認できました。
4. アプリケーションの再起動
PM2で管理していたBotアプリケーションを再起動して、変更を反映しました。
pm2 restart all
5. 再発防止策:自動更新の有効化
Let's Encryptの証明書は90日間の有効期限があるため、手動更新だと忘れてしまうリスクがあります。
そこで、自動更新タイマーを有効化することで、再発を防止しました。
# 自動更新タイマーを有効化
systemctl enable certbot-renew.timer
# タイマーを起動
systemctl start certbot-renew.timer
この設定により、certbotが定期的に証明書の有効期限をチェックし、必要に応じて自動更新してくれるようになります。
この経験から学んだこと
- 証明書には有効期限があることを意識する必要がある
- 自動更新の設定は必須(手動管理は忘れるリスクが高い)
- 証明書エラーが発生したら、まず
curl -vやopenssl s_clientで状態確認 - Let's Encryptの証明書は90日ごとに更新が必要
では、ここからHTTPS通信の仕組みを詳しく見ていきましょう。
HTTPSとは何か
HTTPSは「HTTP + TLS」という構成で、通信内容を暗号化することで盗聴や改ざんを防ぎます。HTTP自体には暗号化機能がないため、TLSによる暗号化層が必須となっています。
HTTP通信(平文)
ブラウザ ←→ サーバー
↓
誰でも読める・改ざん可能
HTTPS通信(暗号化)
ブラウザ ←[TLS暗号化]→ サーバー
↓
暗号化により保護
HTTPとHTTPSの違い
| 項目 | HTTP | HTTPS |
|---|---|---|
| 暗号化 | なし | あり(TLS) |
| ポート番号 | 80 | 443 |
| URL | http:// |
https:// |
| 安全性 | 低い | 高い |
| 証明書 | 不要 | 必要 |
SSLとTLSの関係
SSLはTLSの前身プロトコルで、現在は脆弱性のため非推奨です。現代のHTTPSで使用されているのはTLS1.2 / TLS1.3です。歴史的な事情から「SSL/TLS」という表記が残っています。
プロトコルの歴史
SSL 1.0(未公開) → SSL 2.0(脆弱) → SSL 3.0(脆弱)
↓
TLS 1.0 → TLS 1.1 → TLS 1.2 → TLS 1.3
(非推奨) (非推奨) (現役) (最新・推奨)
重要: 現在「SSL」という用語が使われていても、実際にはTLSを指していることがほとんどです。
HTTPSの通信フロー(概要)
HTTPSの接続は以下の手順で確立されます。
- TLS接続開始: ブラウザがサーバーにTLS通信を開始
- 証明書の提示: サーバーが自身の証明書を送信
- 証明書の検証: ブラウザが証明書の正当性を確認(CA署名のチェック)
- 鍵交換: ECDHE方式により秘密の共通鍵を安全に共有
- 暗号化通信開始: 共通鍵を使った高速な暗号化通信を開始
この中でも最も重要なのが**「鍵交換」**です。
鍵交換とは何か
高速に暗号化するためには「共通鍵(対称鍵)」が必要ですが、これをネット上でそのまま送ると盗まれてしまいます。そこで、送らずに同じ鍵を持つ仕組みが作られています。
なぜ共通鍵が必要なのか?
暗号化方式には2種類あります。
| 暗号化方式 | 鍵の種類 | 速度 | 用途 |
|---|---|---|---|
| 共通鍵暗号 | 同じ鍵で暗号化・復号 | 高速 | データ本体の暗号化 |
| 公開鍵暗号 | 別の鍵で暗号化・復号 | 低速 | 鍵交換・署名 |
問題点: 共通鍵をそのまま送ると盗聴される
❌ 単純に送る場合
クライアント --[共通鍵: ABC123]→ サーバー
↑
盗聴者も入手可能!
解決策: Diffie-Hellman系の鍵交換(ECDHE)を使用
これを実現するのが、**Diffie–Hellman系の鍵交換(ECDHE)**です。
ECDHEでの鍵交換の仕組み
ECDHEでは次のように鍵を生成します。
鍵交換のステップ
重要なポイント
- 秘密の値 A と B は絶対に送られません
- 公開されるのは G×A と G×B のみ
- 公開情報から A や B を逆算するのは**「離散対数問題」のため実質不可能**
- 各自が「相手の公開値 × 自分の秘密値」を計算
- 結果として G×A×B という同じ値に到達する
数学的な例(簡略化)
実際の計算は楕円曲線上で行われますが、概念を理解するための簡単な例:
公開値 G = 5 (共通の基準値)
【クライアント側】
秘密値 A = 3
公開値 = 5³ = 125
相手の公開値 343 に秘密値を適用: 343³ = ...
【サーバー側】
秘密値 B = 7
公開値 = 5⁷ = 343
相手の公開値 125 に秘密値を適用: 125⁷ = ...
→ 数学的に同じ値 5²¹ に到達
つまり、秘密の値 A と B は別々なのに、数学的に同じ共通鍵が得られるという仕組みが成り立っています。
なぜ安全なのか?
盗聴者が知り得る情報:
- G(基準値)
- G×A(クライアントの公開値)
- G×B(サーバーの公開値)
盗聴者が知りたい情報:
- A または B(秘密値)
- G×A×B(共通鍵)
G×A から A を求めるのは「離散対数問題」
→ 現代のコンピュータでは実質的に解けない(数百年かかる)
共通鍵での暗号化
鍵交換が完了すると、通信はすべて以下の流れで行われます。
【送信時】
平文データ → [共通鍵で暗号化] → 暗号文 → 送信
【受信時】
受信 → 暗号文 → [同じ共通鍵で復号] → 平文データ
共通鍵暗号の利点
- 送信側: 共通鍵で暗号化
- 受信側: 同じ共通鍵で復号
- 共通鍵暗号は高速なため、大量データの暗号化に向いています
代表的な共通鍵暗号アルゴリズム:
- AES(Advanced Encryption Standard)
- ChaCha20
Let's Encryptが果たす役割
HTTPSではサーバーが正当なサイトであることを証明するため、証明書を提示します。証明書は認証局(CA: Certificate Authority)が発行し、その中でもLet's Encryptは無料で利用できるため普及しています。
証明書の役割
証明書には以下の情報が含まれます:
- ドメイン名: example.com
- 公開鍵: サーバーの公開鍵
- 有効期限: 2025/12/31まで
- 発行者: Let's Encrypt
- 署名: CAの秘密鍵で署名された値
ブラウザは「CAの公開鍵」で署名を検証し、改ざんされていないことを確認します。
Let's Encryptの認証方法
Let's Encryptは次の方法でドメイン所有者を認証します。
1. HTTP-01チャレンジ
[1] Let's Encrypt → 「このファイルを配置して」
ファイル名: ランダム文字列
内容: トークン
[2] サーバー管理者 → http://example.com/.well-known/acme-challenge/[ランダム文字列]
にファイルを配置
[3] Let's Encrypt → アクセスして内容を確認
✅ 正しい → 証明書発行
2. DNS-01チャレンジ
[1] Let's Encrypt → 「このDNS TXTレコードを追加して」
_acme-challenge.example.com
値: トークン
[2] ドメイン管理者 → DNSサーバーにTXTレコード追加
[3] Let's Encrypt → DNS照会で確認
✅ 正しい → 証明書発行
3. TLS-ALPN-01チャレンジ
特定のTLS応答を返すことで認証
(主にポート80が使えない環境向け)
これらの応答が正しければ、「このドメインを実際に管理している」と判断され、証明書が発行されます。
証明書チェーン
信頼の連鎖の仕組み:
ルートCA (信頼の起点)
|
| 署名
v
中間CA (Let's Encrypt)
|
| 署名
v
サーバー証明書 (example.com)
ブラウザはルートCAを信頼しているため:
- 中間CAの署名を検証
- サーバー証明書の署名を検証
- ✅ すべて検証できれば信頼できる!
全体のフロー図
最後に、HTTPS通信全体の流れをまとめます。
まとめ
本記事で学んだ重要なポイント:
1. HTTPSの基本構造
- HTTPSはHTTP + TLSで構成される
- SSLは旧規格で、現在はTLS1.2/1.3が主流
2. 鍵交換の仕組み
- ECDHEにより"秘密を送らずに"共通鍵を共有できる
- 共通鍵は G×A×B のように数学的に一致する
- 公開値から秘密値を逆算するのは実質不可能(離散対数問題)
3. 暗号化の流れ
- 鍵交換で共通鍵を確立
- 共通鍵暗号(AES等)で高速に通信を暗号化
4. 証明書の役割
- Let's Encryptは無料の認証局として証明書を発行
- ドメイン所有を確認することでサイトの正当性を保証
- ブラウザはCA署名を検証して証明書を信頼
HTTPS通信は、数学と暗号技術の力で安全性を担保していることがわかります。この仕組みにより、私たちは安心してWeb上で個人情報やクレジットカード情報をやり取りできるのです。
参考資料
- RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
- Let's Encrypt公式ドキュメント
- 楕円曲線ディフィー・ヘルマン鍵共有(ECDH)
この記事が、HTTPS通信の仕組み理解の助けになれば幸いです。

