curlコマンドで学ぶHTTPS:基本の紹介と実践
はじめに
インターネットは私たちの生活やビジネスに不可欠なインフラとなりました。ウェブサイトの閲覧、オンラインショッピング、バンキング、メールの送受信など、日々多くの情報がネットワーク上を流れています。その中で、情報の「安全性」は非常に重要な課題です。特に、個人情報やクレジットカード情報、企業の機密情報といったデリケートな情報をやり取りする際には、その情報が第三者によって盗み見られたり、改ざんされたりしないようにする必要があります。
そこで登場するのが HTTPS (Hypertext Transfer Protocol Secure) です。HTTPSは、ウェブ通信の基本プロトコルであるHTTPにセキュリティ機能を追加したもので、通信の暗号化、認証、完全性を保証します。これにより、ユーザーはより安心してウェブサービスを利用できるようになります。
しかし、「HTTPS」という言葉はよく聞くけれど、その仕組みや背後で何が起こっているのかを具体的に理解している人は意外と少ないかもしれません。ウェブブラウザを使っていれば、URLの左横に表示される鍵マークを見て「安全な接続だな」と判断することはできますが、その鍵マークがどのようにして実現されているのかを知ることは、インターネットの安全性を理解する上で非常に役立ちます。
この記事では、コマンドラインツールである curl を使って、HTTPSの基本原理と動作を実際に「見て」「体験して」学ぶことを目的とします。curlは非常に多機能なHTTPクライアントであり、その詳細な出力を利用することで、通常はブラウザの裏側で自動的に行われているHTTPSの確立プロセスや、デジタル証明書の検証などを、ステップ・バイ・ステップで確認することができます。
curlの基本的な使い方から、HTTPS通信の内部で行われるTLSハンドシェイクの様子、デジタル証明書の役割と検証、そしてよくあるHTTPSに関するエラーの原因までを、具体的なコマンド例とその出力結果を交えながら詳しく解説していきます。
この記事を読めば、単に「HTTPSは安全らしい」という表面的な理解から一歩進んで、「なぜHTTPSが安全なのか」「どのように安全が保たれているのか」を、技術的な側面から具体的に理解できるようになるはずです。
記事の対象読者:
- ウェブ開発者、インフラエンジニアを目指す方
- ウェブセキュリティに興味がある方
- HTTPやネットワークの仕組みをより深く理解したい方
- curlコマンドの便利な使い方を学びたい方
それでは、まずはHTTPSの基盤となるHTTPについて簡単に振り返り、なぜHTTPSが必要なのかを確認するところから始めましょう。
HTTPの基本(HTTPS理解の前提として)
HTTPSを理解するためには、まずその基盤となるHTTP(Hypertext Transfer Protocol)について簡単に把握しておく必要があります。
HTTPは、クライアント(主にウェブブラウザ)とサーバー(ウェブサーバー)間で情報をやり取りするためのプロトコルです。ユーザーがウェブサイトのURLをクリックしたり、アドレスバーにURLを入力したりすると、ブラウザは指定されたウェブサーバーに対してHTTPリクエストを送信します。サーバーはそのリクエストを処理し、HTMLファイルや画像ファイルなどのデータをHTTPレスポンスとしてクライアントに返します。
HTTPは「ステートレス」なプロトコルです。これは、サーバーが個々のリクエストに対して独立して応答し、過去のリクエストの状態(例えば、ログインしているユーザーやカートに入れた商品など)を基本的に保持しないことを意味します。セッション管理などは、Cookieなどの別の仕組みを使って実現されます。
HTTPの基本的な流れ:
- クライアント(ブラウザ)がサーバーに接続要求(TCP接続の確立)。
- クライアントがHTTPリクエストを送信(例:
GET /index.html HTTP/1.1
)。 - サーバーがHTTPレスポンスを送信(例:
HTTP/1.1 200 OK
に続いてHTMLデータなど)。 - 接続を閉じるか、次のリクエストのために維持する。
HTTPの課題:なぜHTTPSが必要なのか?
HTTPはシンプルで拡張性が高いプロトコルですが、いくつかの重要な課題を抱えています。最も大きな課題は以下の点です。
- 平文通信: HTTPでやり取りされるデータは、基本的に平文(暗号化されていない状態)です。これは、リクエストヘッダー、レスポンスヘッダー、そしてリクエストボディやレスポンスボディに含まれるデータ(ユーザー名、パスワード、クレジットカード番号、メールの内容など)が、ネットワーク上の第三者によって容易に盗み見られる可能性があることを意味します。公衆無線LANなど、不特定多数が利用するネットワークでは特に危険です。
- 改ざんの可能性: 平文で通信されるデータは、通信経路上の第三者によって内容を不正に改ざんされる可能性があります。例えば、サーバーが送った正規のHTMLに悪意のあるスクリプトが挿入されたり、ダウンロードしようとしているファイルが別のものに差し替えられたりする可能性があります。
- 通信相手のなりすまし: クライアントはサーバーのIPアドレスに基づいて接続を行いますが、そのIPアドレスを持つサーバーが本当に意図した正当なサーバーであるかを保証する仕組みがHTTPにはありません。悪意のある第三者が正規のサーバーになりすまし、ユーザーから情報を騙し取る「フィッシング」のリスクが存在します。
これらの課題に対処するために開発されたのが、セキュリティ機能を追加したHTTPSです。
HTTPSとは何か?
HTTPSは、HTTPプロトコルを SSL/TLS と呼ばれる暗号化プロトコル上で動作させるものです。正式名称は Hypertext Transfer Protocol Secure ですが、「HTTP over SSL/TLS」と表現されることもあります。SSL(Secure Sockets Layer)はTLS(Transport Layer Security)の先行バージョンであり、現在はよりセキュアなTLSの使用が主流です。しかし、歴史的な経緯から「SSL」という言葉が使われることも多く、「SSL/TLS」とまとめて呼ばれるのが一般的です。
SSL/TLSプロトコルの役割
SSL/TLSは、アプリケーション層(HTTPなど)とトランスポート層(TCPなど)の間に位置し、その上でやり取りされるデータを保護する役割を果たします。SSL/TLSが提供する主なセキュリティ機能は以下の3つです。
- 暗号化 (Encryption): クライアントとサーバー間の通信内容を暗号化します。これにより、通信経路上の第三者がデータを盗み見ても、その内容を解読できなくなります。機密情報の漏洩を防ぎます。
- 認証 (Authentication): 接続しようとしているサーバーが、ユーザーが意図した正当なサーバーであることを証明します。主にデジタル証明書を用いてサーバーの身元を確認します。これにより、悪意のある第三者によるサーバーのなりすましを防ぎます。また、オプションでクライアント側もサーバーに対して自身の身元を証明するクライアント証明書認証を行うことも可能です。
- 完全性 (Integrity): 通信途中でデータが改ざんされていないことを確認します。メッセージ認証コード(MAC)などを使用して、受信したデータが送信された通りのものであることを検証します。これにより、悪意のある第三者によるデータの改ざんを防ぎます。
HTTPSはこれらのSSL/TLSの機能を利用することで、前述したHTTPの課題(平文通信、改ざん、なりすまし)を解決します。
HTTPSが解決するHTTPの課題のまとめ:
- 平文通信 → 暗号化: 通信内容を暗号化し、盗聴を防ぐ。
- 改ざんの可能性 → 完全性の保証: データが改ざんされていないことを検知できる。
- 通信相手のなりすまし → サーバー認証: 接続先のサーバーが正当であることを証明書で確認できる。
URLが http
から https
に変わる意味
ウェブサイトにHTTPSが導入されている場合、URLのスキーム部分が http://
から https://
に変化します。これは、そのサイトとの通信がSSL/TLSによって保護されていることを示します。また、標準で使用されるポート番号もHTTPの80番からHTTPSの443番に変わります(明示的に指定しない場合)。
https://
で始まるURLにアクセスしようとしたとき、ブラウザやcurlのようなクライアントは、通常のHTTP接続ではなく、まずSSL/TLSハンドシェイクという特別なプロセスを開始して、暗号化された安全な通信路を確立しようとします。
ブラウザでのHTTPSの表示
現代のほとんどのブラウザでは、HTTPSで保護されたサイトにアクセスすると、アドレスバーに鍵マークが表示されます。この鍵マークをクリックすると、証明書に関する詳細情報(誰に発行されたか、有効期間はいつか、発行者は誰かなど)を確認できることが一般的です。もし証明書に問題があったり、HTTPSで接続できていなかったりする場合は、警告が表示されるなど、ユーザーに注意を促すような表示になります。
HTTPSの仕組みの概観
HTTPSのセキュリティを支えるSSL/TLSプロトコルの仕組みは複雑ですが、その核心は以下の要素にあります。
- TLSハンドシェイク: クライアントとサーバーが安全な通信を開始する前に、互いの能力を確認し、暗号化方式を取り決め、通信に必要な鍵を生成・共有し、相手を認証する一連のプロセスです。
- 共通鍵暗号方式と公開鍵暗号方式の組み合わせ: 実際のデータの暗号化には高速な共通鍵暗号方式(暗号化と復号に同じ鍵を使う)が使われますが、その共通鍵を安全に共有するために公開鍵暗号方式(暗号化に使う鍵(公開鍵)と復号に使う鍵(秘密鍵)が異なる)が使われます。
- デジタル証明書: サーバー(時にはクライアント)の身元を証明するための電子的な証明書です。公開鍵情報や所有者の情報などが含まれており、信頼できる第三者機関(認証局)によって署名されています。
- 認証局 (CA) と信頼の階層: デジタル証明書を発行・管理する信頼できる第三者機関です。ブラウザやOSには、主要な認証局の公開鍵があらかじめ「信頼されたルート証明書」としてインストールされており、この信頼の連鎖を利用してサーバー証明書の正当性を検証します。
これらの要素が組み合わさることで、安全なHTTPS通信が実現されます。
TLSハンドシェイク(簡略版):
TLSハンドシェイクは、クライアントとサーバーが初めて安全な接続を確立する際に行われるプロセスです。非常に多くのステップがありますが、基本的な流れは以下のようになります。
- Client Hello: クライアントは、サポートするTLSのバージョン、暗号スイート(暗号化方式、鍵交換方式、ハッシュ関数などの組み合わせ)、ランダムなデータなどをサーバーに送信します。
- Server Hello: サーバーは、クライアントが提案した中から合意できたTLSバージョン、選択した暗号スイート、サーバー側のランダムなデータなどを返信します。
- Certificate: サーバーは、自身のデジタル証明書をクライアントに送信します。証明書チェーン(サーバー証明書、中間CA証明書など)が送られるのが一般的です。
- Server Key Exchange (Ephemeral DHなどの場合): 鍵交換に必要なサーバー側の情報を送信します。
- Server Hello Done: サーバーはハンドシェイクの初期段階でのメッセージを完了したことを通知します。
- Client Key Exchange: クライアントは、共通鍵を生成するために必要な情報(例えば、公開鍵暗号方式で暗号化した共通鍵の元となるデータ、あるいはDiffie-Hellman鍵交換に必要な情報)をサーバーに送信します。
- Change Cipher Spec: クライアントは、これ以降の通信を合意した暗号スイートと生成した共通鍵で暗号化することをサーバーに通知します。
- Finished: クライアントは、これまでのハンドシェイクメッセージのハッシュ値を、新しく確立された安全な通信路で暗号化して送信し、ハンドシェイクの成功を確認します。
- Change Cipher Spec & Finished: サーバーも同様に通知と確認を行います。
このハンドシェイクが成功すると、クライアントとサーバーは同じ共通鍵を共有し、これ以降のアプリケーションデータ(HTTPリクエストやレスポンス)は、この共通鍵を使って暗号化・復号されるようになります。
なぜ共通鍵暗号と公開鍵暗号を組み合わせるのか?
- 共通鍵暗号: 暗号化・復号が高速です。大量のデータを効率的に暗号化するのに適しています。しかし、事前に安全な方法で鍵を共有する必要があります。
- 公開鍵暗号: 鍵の配送問題を解決できます(公開鍵は誰でも知ってよい)。しかし、計算コストが高く、大量のデータの暗号化には不向きです。
SSL/TLSでは、この両方の利点を活用します。まず、公開鍵暗号やDiffie-Hellman鍵交換などの技術を使って、少量のデータ(共通鍵や、共通鍵を生成するための情報)を安全にやり取りします。そして、安全に共有できた共通鍵を使って、実際の大量の通信データを高速な共通鍵暗号で暗号化します。
デジタル証明書と認証局(CA)
サーバーの身元を証明するために使われるのがデジタル証明書です。証明書には、証明書の対象となるエンティティ(ウェブサイトのドメイン名など)、その公開鍵、証明書の発行者(CA)、有効期間などの情報が含まれています。
クライアントは、サーバーから受け取った証明書が、自分が信頼している認証局によって発行されたものであるか、有効期間内であるか、そして証明書に記載されたドメイン名がアクセスしようとしているサイトのドメイン名と一致するかなどを検証します。この検証プロセスを経て、クライアントは接続先のサーバーが正当なサーバーであると判断し、安心して通信を開始します。
認証局は階層構造になっていることが多く、一番上のルート認証局の証明書がブラウザやOSに最初から組み込まれています。サーバー証明書は通常、中間認証局によって発行され、その中間認証局の証明書はさらに上位の認証局によって署名されている、というように、信頼の連鎖(証明書チェーン)をたどってルート認証局に至ります。クライアントはこのチェーン全体を検証します。
curlコマンド入門
いよいよ、このHTTPSの仕組みを実際に見ていくために、curlコマンドを使ってみましょう。
curlとは?
curlは、URLシンタックスを使用してデータを転送するためのコマンドラインツールです。HTTP, HTTPS, FTP, FTPS, SCP, SFTP, TFTP, DICT, TELNET, LDAP, LDAPS, POP3, POP3S, SMTP, SMTPS, RTMP, RTSP, IMAP, IMAPS, FILE, GOPHER など、様々なプロトコルをサポートしています。
ウェブ開発やAPIテスト、ファイルダウンロード、ネットワーク診断など、幅広い用途で利用されており、ほとんどのUNIX系OS(Linux, macOSなど)には標準でインストールされているか、簡単にインストールできます。Windowsでも近年は標準で使えるようになっています。
curlの最大の特徴の一つは、その柔軟性と詳細なデバッグ情報を提供する機能です。特に -v
オプションは、HTTP/HTTPS通信の内部で行われる詳細なやり取りをステップごとに表示してくれるため、プロトコルの学習に非常に役立ちます。
基本的な使い方
curlの基本的な使い方は非常にシンプルです。
bash
curl [URL]
指定したURLに対してHTTP GETリクエストを送信し、そのレスポンスボディ(通常はHTMLコンテンツなど)を標準出力に表示します。
例:HTTPサイトへのアクセス
bash
curl http://example.com/
このコマンドを実行すると、example.com
のトップページのHTMLコンテンツが表示されます。これは暗号化されていない、平文の通信です。
例:HTTPSサイトへのアクセス
bash
curl https://www.google.com/
このコマンドを実行すると、www.google.com
のトップページのHTMLコンテンツが表示されます。こちらはHTTPSによる暗号化された通信です。通常はこのコマンドを実行しても、curlは自動的にSSL/TLSハンドシェイクを行って安全な通信路を確立するため、ユーザーはその裏側で何が起こっているかを知ることはできません。しかし、curlのオプションを使うことで、このプロセスを「見える化」できます。
curlの主要オプション紹介(HTTPS関連)
HTTPSの仕組みを学ぶ上で特に役立つcurlのオプションをいくつか紹介します。
-v, --verbose
: 詳細なデバッグ情報を表示します。これには、TLS/SSLのハンドシェイクの詳細、送受信されるヘッダー、接続情報などが含まれます。HTTPS通信を深く理解するための最も重要なオプションです。-I, --head
: GETリクエストではなくHEADリクエストを送信し、レスポンスヘッダーのみを表示します。これにより、コンテンツ本体を取得せずにHTTP/HTTPSのステータスコードやヘッダー(Strict-Transport-Security
なども含む)を確認できます。-L, --location
: サーバーからのリダイレクト(HTTPステータスコード3xx)を自動的に追跡します。http://...
からhttps://...
へのリダイレクトを確認する際に便利です。-k, --insecure
: SSL/TLS証明書の検証を無効にします。証明書に問題があるサイトにも接続できてしまいます。セキュリティリスクを高めるため、通常は使用すべきではありませんが、証明書検証エラーの挙動を確認したり、自己署名証明書を使った開発環境に接続したりする場合などに一時的に利用することがあります。-E, --cert [certificate format]
: クライアント証明書を指定して、クライアント認証を行います。双方向TLS(mTLS: mutual TLS)の確認などに使用します。--cacert [file]
: 特定のCA証明書ファイルを指定し、サーバー証明書の検証に使用します。--resolve [host:port:address]
: ホスト名を特定のIPアドレスに強制的に解決させます。DNSキャッシュやhostsファイルよりも優先されます。--ciphers [list]
: クライアントが提示する暗号スイートのリストを指定します。特定の暗号スイートの動作確認や脆弱な暗号スイートのテストなどに使えます。--tlsv1.2
,--tlsv1.3
など: 使用するTLSのバージョンを指定します。
これらのオプションを組み合わせることで、HTTPS通信の様々な側面を詳細に観察し、理解を深めることができます。
curlでHTTPSの仕組みを学ぶ(実践編)
それでは、実際にcurlコマンドの -v
オプションを中心に、HTTPS通信の内部を見ていきましょう。有名なウェブサイトに対して -v
オプションを使ってアクセスしてみます。
TLSハンドシェイクの確認 (-v
オプション)
最も基本的なHTTPSサイトへの -v
アクセスは以下のようになります。
bash
curl -v https://www.example.com/
このコマンドを実行すると、HTMLコンテンツの表示に加えて、標準エラー出力に詳細なデバッグ情報が大量に表示されます。出力は環境(curlのバージョン、OS、TLSライブラリなど)によって多少異なりますが、大まかな流れは同じです。
以下に、-v
オプションの出力例とその読み解き方のポイントを示します。
“`
* Trying 93.184.216.34:443… <– 接続先のIPアドレスとポート(443)
* Connected to www.example.com (93.184.216.34) port 443 (#0) <– 接続確立
- ALPN: offers h2
- ALPN: offers http/1.1 <– アプリケーション層プロトコルネゴシエーション (ALPN)。HTTP/2やHTTP/1.1を提案。
- TLSv1.3 (IN), TLS handshake, Client hello (1): <– TLSv1.3ハンドシェイク開始、Client Hello送信
- TLSv1.3 (OUT), TLS handshake, Server hello (2): <– Server Hello受信
- TLSv1.3 (OUT), TLS change cipher spec (1): <– Server Change Cipher Spec受信
- TLSv1.3 (OUT), TLS handshake, Finished (4): <– Server Finished受信
- TLSv1.3 (IN), TLS change cipher spec (1): <– Client Change Cipher Spec送信
-
TLSv1.3 (IN), TLS handshake, Finished (4): <– Client Finished送信
-
SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384 <– 確立されたTLSバージョンと暗号スイート
- ALPN: server accepted http/1.1 <– サーバーが合意したALPNプロトコル
- Server certificate: <– サーバー証明書の情報開始
- subject: C=US; O=Akamai Technologies, Inc.; CN=www.example.com <– 証明書の所有者情報 (Subject)
- start date: Feb 8 00:00:00 2024 GMT <– 証明書有効期間の開始日
- expire date: Feb 10 23:59:59 2025 GMT <– 証明書有効期間の終了日
- subjectAltName: host “www.example.com” matched cert’s “www.example.com” <– Subject Alternative Name (SAN) の確認。ホスト名が証明書のSAN/CNと一致するか検証。
- issuer: C=US; O=Akamai Technologies, Inc.; CN=Akamai Technologies ECC CA – 3 <– 証明書の発行者情報 (Issuer)
- SSL certificate verify ok. <– 証明書検証に成功!
GET / HTTP/1.1 <– TLS上で暗号化されて送信されるHTTPリクエストヘッダー
Host: www.example.com
User-Agent: curl/7.81.0
Accept: /
< HTTP/1.1 200 OK <– TLS上で暗号化されて受信されるHTTPレスポンスヘッダー
< Content-Encoding: gzip
< Accept-Ranges: bytes
< Cache-Control: max-age=604800
< Content-Type: text/html
< Date: Mon, 26 Feb 2024 10:00:00 GMT
< Etag: “3147526947+gzip”
< Expires: Mon, 04 Mar 2024 10:00:00 GMT
< Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
< Server: ECS (iad/187E)
< Vary: Accept-Encoding
< X-Cache: HIT
< Content-Length: 648
<
{ [648 bytes data] <– レスポンスボディ(暗号化されているため内容は表示されないがサイズがわかる)
* Connection #0 to host www.example.com left intact <– 接続終了
“`
読み解きのポイント:
* Trying ...
,* Connected ...
: 接続先のIPアドレス、ポート、ホスト名が表示され、TCP接続が確立されたことがわかります。HTTPSの標準ポートは443です。* ALPN: offers ...
: クライアントがサポートするアプリケーション層プロトコル(HTTP/2やHTTP/1.1など)をサーバーに提示しています。* TLSv1.3 (IN/OUT), TLS handshake, ...
: TLSハンドシェイクの進行状況です。(IN)は受信、(OUT)は送信を示します。Client hello
,Server hello
,Change cipher spec
,Finished
といったハンドシェイクの主要なステップが確認できます。ここから、クライアントとサーバーが互いのTLS能力や暗号スイートについて交渉している様子が見て取れます。* SSL connection using ...
: ハンドシェイクが成功し、確立されたTLSバージョン(例: TLSv1.3)と選択された暗号スイート(例: AEAD-AES256-GCM-SHA384)が表示されます。暗号スイートは通常、「鍵交換アルゴリズム」「署名アルゴリズム」「共通鍵暗号化アルゴリズム」「認証(MAC)アルゴリズム」の組み合わせを示します。この例では、TLSv1.3のAEAD (Authenticated Encryption with Associated Data) モードでAES 256ビットキー、GCM(Galois/Counter Mode)認証、SHA384ハッシュ関数を使った暗号スイートが使われています。* ALPN: server accepted ...
: サーバーがどのアプリケーション層プロトコルを使用することに合意したかが表示されます。* Server certificate:
: ここから、サーバーから受信したデジタル証明書に関する情報が表示されます。subject
: 証明書の所有者情報です。通常はウェブサイトのドメイン名(Common Name – CN)や、複数のドメイン名をリストしたSubject Alternative Name (SAN) が含まれます。start date
,expire date
: 証明書の有効期間です。クライアントは現在日時がこの期間内にあるかを確認します。subjectAltName: host "..." matched cert's "..."
: curlはアクセスしたホスト名 (www.example.com
) が証明書のSANやCNフィールドと一致するかどうかを検証し、その結果を表示します。これが非常に重要です。 フィッシングサイトなどでは、偽のサイトの証明書を使っている場合、ここのドメイン名が一致しないことがよくあります。issuer
: 証明書を発行した認証局の情報です。SSL certificate verify ok.
: curlが証明書の有効性(信頼されたCAからの発行か、有効期間内か、ホスト名と一致するかなど)を検証し、問題がなかったことを示しています。
> GET / HTTP/1.1 ...
: TLSハンドシェイクの完了後、クライアントからサーバーに送信されるHTTPリクエストヘッダーです。このヘッダーは、確立されたTLS通信路によって暗号化されて送信されています。< HTTP/1.1 200 OK ...
: サーバーからクライアントに返されるHTTPレスポンスヘッダーです。これも暗号化されて受信されます。{ [ ... bytes data]
: レスポンスボディのデータです。-v
オプションでは、バイナリデータや大量のテキストデータは内容が表示されず、そのサイズだけが表示されることがあります。
-v
オプションを使うことで、TLSハンドシェイクのステップ、使用される暗号スイート、そして証明書の詳細情報やその検証結果まで、HTTPS通信の核心部分を具体的に確認できることがわかります。
デジタル証明書の確認 (-v
オプションの詳細)
-v
オプションの出力に含まれる証明書情報をもう少し詳しく見てみましょう。特に証明書チェーンと各フィールドの意味を理解することは重要です。
多くのウェブサイトでは、サーバー証明書だけでなく、中間CA証明書もクライアントに送信します。これは、クライアントがサーバー証明書からルートCA証明書まで信頼の連鎖をたどれるようにするためです。-v
オプションの出力には、受信した証明書が連鎖して表示されることがあります(証明書の数や形式によって表示の仕方は異なります)。
例えば、以下のような情報が含まれることがあります。
* Server certificate:
* subject: C=US; ST=California; L=Mountain View; O=Google Trust Services LLC; CN=Google Trust Services LLC <-- 中間CA証明書 (Issuer for the next cert)
* issuer: O=GlobalSign nv-sa; CN=GlobalSign Root CA - R2 <-- ルートCA証明書 (Issuer for the current cert)
* subject: C=US; O=Google Trust Services LLC; CN=GTS CA 1C3 <-- 中間CA証明書 (Issuer for the next cert)
* issuer: C=US; O=Google Trust Services LLC; CN=Google Trust Services LLC <-- 一つ上の証明書
* subject: CN=*.google.com <-- サーバー証明書 (Subject)
* issuer: C=US; O=Google Trust Services LLC; CN=GTS CA 1C3 <-- 一つ上の証明書 (Intermediate CA)
...
* SSL certificate verify ok.
この例では、*.google.com
のサーバー証明書が GTS CA 1C3
という中間CAによって発行され、その GTS CA 1C3
は Google Trust Services LLC
という別の中間CAによって発行され、それがさらに GlobalSign Root CA - R2
というルートCAによって発行されている、というチェーン構造が見て取れます(表示順は環境により逆順の場合もあります)。curlは、最終的にブラウザやOSに組み込まれた信頼されたルートCA証明書リストの中に GlobalSign Root CA - R2
が存在するかを確認し、チェーン全体が有効であれば「SSL certificate verify ok」と表示します。
証明書の主なフィールド:
Subject
: 証明書の所有者。アクセスしようとしているサイトのドメイン名(CNやSAN)がここに含まれている必要があります。ワイルドカード証明書(例:*.google.com
)や複数のドメインを含むSAN証明書が一般的です。Issuer
: この証明書を発行し、署名した認証局。Validity
: 証明書が有効な期間 (start date
からexpire date
まで)。Public Key Info
: 証明書所有者の公開鍵情報。この公開鍵は、共通鍵の安全な交換や、サーバー証明書の署名検証に使われます。Subject Alternative Name (SAN)
: 1つの証明書で保護される複数のホスト名やIPアドレスを指定する拡張フィールド。最近はこちらがCNよりも優先して使われることが多く、ワイルドカード (*.example.com
) もSANで指定されるのが一般的です。Key Usage
,Extended Key Usage
: 証明書がどのような目的で使用できるかを指定します(例: サーバー認証、クライアント認証、コード署名など)。Basic Constraints
: この証明書がCA証明書であるかどうかを指定します。CA:TRUE
となっていれば、他の証明書に署名できるCA証明書であることを示します。
curlは、これらのフィールドを読み取り、OSやcurlに設定された信頼ストア(信頼されたCA証明書リスト)を参照して、証明書の検証を行います。
証明書の検証エラーを体験する (-k
オプション)
curlはデフォルトで、受信したサーバー証明書が正当なものであるか、厳格に検証を行います。もし検証に失敗した場合、curlは接続を中断し、エラーメッセージを表示します。
よくある証明書検証エラーの原因としては、以下のようなものがあります。
- 期限切れの証明書: 証明書の有効期間が過ぎている場合。
- ホスト名不一致: 証明書に記載されているドメイン名(CNまたはSAN)が、アクセスしようとしているホスト名と一致しない場合。
- 自己署名証明書: 信頼できる認証局ではなく、サーバー管理者自身が署名した証明書の場合。
- 証明書チェーンの不備: 中間CA証明書が欠落しているなど、ルートCAまで信頼の連鎖をたどれない場合。
- 失効した証明書: 証明書が有効期間内であっても、発行者によって失効リスト(CRL)に載せられていたり、OCSPで無効と報告されたりしている場合。
これらのエラーが発生するHTTPSサイトに、通常通りcurlでアクセスしてみましょう(自己署名証明書を使ったローカル環境など)。
bash
curl https://self-signed.example.local/
おそらく、以下のようなエラーメッセージが表示され、接続が中断されるでしょう。
“`
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
“`
このエラーメッセージは「自己署名証明書だから検証に失敗した」ことを明確に示しています。subject name does not match hostname
と表示されればホスト名不一致、certificate has expired
と表示されれば期限切れなど、エラーメッセージから原因を推測できます。
-k, --insecure
オプション:
ここで -k
オプションを使ってみます。
bash
curl -k https://self-signed.example.local/ -v
-k
オプションを付けると、curlは証明書の検証をスキップします。検証エラーは発生せず、接続が続行されます。-v
オプションを併用すると、証明書に関する情報は表示されますが、検証結果を示す部分が異なることがわかります。
...
* Server certificate:
... (証明書情報は表示される)
* SSL certificate verify result: self signed certificate (18), continuing anyway. <-- 検証エラーが発生したが、続行している
...
SSL certificate verify result: ... continuing anyway
という表示が、-k
オプションの効果です。
重要: -k
オプションは本番環境や信頼できないサイトへのアクセスには絶対に使用しないでください。 証明書の検証をスキップするということは、「接続先が本当に意図した正当なサーバーであるか」を確認しないということです。これは、悪意のあるサーバーへの接続や、中間者攻撃によって偽の証明書を提示された場合でも、それに気づかずに通信を続行してしまうという非常に高いリスクを伴います。-k
オプションは、あくまでテストや特定の状況下でのデバッグのために存在します。
特定のCA証明書を使って認証する (--cacert
オプション)
自己署名証明書や、社内独自の認証局が発行した証明書など、OSやブラウザのデフォルトの信頼ストアに含まれていないCAによって署名された証明書を検証したい場合があります。このような場合に --cacert
オプションを使用します。
まず、検証に使用したいCA証明書をPEM形式のファイルとして用意します(例: my-ca.pem
)。
bash
curl --cacert my-ca.pem https://internal-server.mycompany.local/ -v
このコマンドを実行すると、curlはシステムの信頼ストアに加えて、指定した my-ca.pem
ファイルに含まれるCA証明書を使って、サーバー証明書の検証を行います。サーバー証明書が my-ca.pem
で指定したCAによって正しく署名されていれば、「SSL certificate verify ok」となるでしょう。
クライアント証明書認証 (-E
オプション)
通常のHTTPSでは、サーバーだけが証明書を使って自身の身元を証明しますが、より高いセキュリティが求められる場面では、クライアント側も自身の身元を証明するクライアント証明書認証(双方向TLS、mTLS)が使用されることがあります。例えば、企業のイントラネットへのアクセスや、API連携などで利用されます。
curlは -E
または --cert
オプションを使って、クライアント証明書を指定して接続することができます。クライアント証明書ファイルと秘密鍵ファイルが必要になります。これらは通常、PEM形式で提供されます。
bash
curl -E /path/to/client.pem --key /path/to/client-key.pem https://secure-api.example.com/resource -v
証明書ファイルと秘密鍵ファイルが単一のPEMファイルに含まれている場合は、-E
オプションだけで指定できます。
bash
curl -E /path/to/client-cert-and-key.pem https://secure-api.example.com/resource -v
-v
オプションを使うと、クライアント証明書がサーバーに提示され、サーバーがそれを検証する(概念的に)様子の一部が出力されることがあります。サーバー側がクライアント証明書を要求しているにもかかわらず、クライアントが証明書を提示しない場合や、提示した証明書がサーバーによって信頼されない場合は、接続エラーとなるか、アクセス拒否されることになります。
HTTP Strict Transport Security (HSTS) の確認
HSTS (HTTP Strict Transport Security) は、ウェブサイトがブラウザに対して「今後のアクセスは必ずHTTPSで行うように」と指示するためのセキュリティメカニズムです。これにより、ユーザーが誤ってHTTPでアクセスしようとした場合でも、ブラウザが自動的にHTTPSに切り替えるようになります。中間者攻撃によるダウングレード攻撃(強制的に安全でないHTTP通信に切り替えさせる攻撃)を防ぐのに有効です。
HSTSは、サーバーからのHTTPレスポンスヘッダーに含まれる Strict-Transport-Security
ヘッダーによって設定されます。curlの -I
オプション(ヘッダーのみ表示)や -v
オプション(詳細表示)を使うことで、このヘッダーが存在するか確認できます。
例えば、Googleのサイトに -I
オプションでアクセスしてみましょう。
bash
curl -I https://www.google.com/
出力されるヘッダーの中に、以下のような行が見つかるはずです。
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Strict-Transport-Security
: HSTSヘッダーのフィールド名。max-age=31536000
: この設定を記憶しておく期間(秒)。31536000秒は1年間です。includeSubDomains
: この設定がサブドメインにも適用されることを示します。preload
: このドメインをHSTSプリロードリスト(主要なブラウザにあらかじめ組み込まれているリスト)に含めることができることを示します。
ブラウザは一度このヘッダーを受け取ると、指定された期間内は、ユーザーが http://www.google.com
と入力しても、自動的に https://www.google.com
に書き換えてアクセスするようになります。
ただし、curlはこのHSTSヘッダーを解釈して、将来のアクセスで自動的にHTTPSに切り替えるようなブラウザと同様の挙動は行いません。curlはあくまでそのリクエスト単体でヘッダーを受信するだけです。HSTSは主にブラウザのセキュリティ機能として機能します。curlで確認できるのは、サーバーがHSTSヘッダーを送信しているかどうかです。
リダイレクトとHTTPS (-L
オプション)
多くのウェブサイトは、ユーザーが http://example.com
のようにHTTPでアクセスした場合に、自動的に https://example.com
へリダイレクトするように設定されています。これは、安全でないHTTPでの通信を避けるためです。
curlでこのリダイレクトの挙動を確認するには、-L
オプション(--location
)を使用します。-L
オプションは、サーバーからHTTPステータスコード3xx(リダイレクトを示すコード)を受け取った際に、レスポンスの Location
ヘッダーに指定されたURLへ自動的に再リクエストを行います。
bash
curl -L http://www.example.com/ -v
-v
オプションを併用すると、最初にHTTPでアクセスし、その後リダイレクトされてHTTPSでアクセスし直す様子を確認できます。
“`
* Trying 93.184.216.34:80… <– 最初はHTTPポート(80)に接続
* Connected to www.example.com (93.184.216.34) port 80 (#0)
GET / HTTP/1.1
Host: www.example.com
User-Agent: curl/7.81.0
Accept: /< HTTP/1.1 301 Moved Permanently <– 301 Moved Permanently レスポンスを受信
< Cache-Control: max-age=2592000
< Content-Type: text/html; charset=UTF-8
< Date: Mon, 26 Feb 2024 10:00:00 GMT
< Expires: Wed, 27 Mar 2024 10:00:00 GMT
< Location: https://www.example.com/ <– リダイレクト先URL (HTTPS!)
< Server: ECS (iad/187E)
< Content-Length: 227
<
* Issue another request to this URL: ‘https://www.example.com/’ <–-L
オプションによりリダイレクト先へ再リクエスト
* Trying 93.184.216.34:443… <– 今度はHTTPSポート(443)に接続
* Connected to www.example.com (93.184.216.34) port 443 (#1)
… (ここから先の出力は、前述のHTTPSアクセス時の-v
出力と同様になります)
“`
この出力から、最初にHTTPでアクセスしたが、サーバーが301リダイレクトでHTTPSのURLを返し、-L
オプションのおかげでcurlがそのHTTPS URLに自動的に再接続した様子が明確にわかります。最終的に安全なHTTPSでデータが取得されています。ただし、最初のリクエスト自体は暗号化されていないHTTPで行われている点には注意が必要です。この初回HTTPアクセスの脆弱性を軽減するのがHSTSです。
HTTPSのセキュリティに関する考慮事項
HTTPSを導入すれば全てが安全になるわけではありません。HTTPSによる保護のレベルは、サーバーとクライアントが合意するSSL/TLSのバージョンや暗号スイート、使用される証明書の強度や管理状況など、様々な要因に依存します。curlを使うことで、これらの設定がどのようになっているかを確認することができます。
- 安全なTLSバージョンと暗号スイートの選択:
- 古いTLSバージョン(SSLv2, SSLv3, TLSv1.0, TLSv1.1)には既知の脆弱性が存在します。現在では TLSv1.2またはTLSv1.3 の使用が推奨されています。curlの
-v
出力でどのバージョンが使われているかを確認しましょう。--tlsv1.2
,--tlsv1.3
オプションで特定のバージョンを指定して接続を試みることもできます。 - 暗号スイートも、鍵長が短いものや、脆弱性が報告されているアルゴリズム(例: RC4、DES、MD5を使った署名など)を含むものは避けるべきです。楕円曲線暗号(ECC)に基づいた鍵交換(ECDHE)や、AES-GCMのような認証付き暗号(AEAD)を含む暗号スイートが推奨されます。
-v
出力で確認できる暗号スイート名を OpenSSLなどのドキュメントやSSL Labsのサイトなどで調べて、安全性を評価できます。curlの--ciphers
オプションで、サーバーが特定の(安全性の低い)暗号スイートをサポートしているかテストすることも可能です。
- 古いTLSバージョン(SSLv2, SSLv3, TLSv1.0, TLSv1.1)には既知の脆弱性が存在します。現在では TLSv1.2またはTLSv1.3 の使用が推奨されています。curlの
- 前方秘匿性 (Forward Secrecy – FS):
- 前方秘匿性を提供する鍵交換方式(DHEやECDHEなど)を使用している場合、過去の通信を記録しておき、将来サーバーの秘密鍵が漏洩したとしても、過去の通信内容が解読されることがありません。
-v
出力で確認できる暗号スイート名にDHE
やECDHE
が含まれていれば、前方秘匿性が有効になっている可能性が高いです。
- 前方秘匿性を提供する鍵交換方式(DHEやECDHEなど)を使用している場合、過去の通信を記録しておき、将来サーバーの秘密鍵が漏洩したとしても、過去の通信内容が解読されることがありません。
- 証明書の失効確認 (OCSP Stapling / CRL):
- 証明書が有効期間内であっても、秘密鍵の漏洩などの理由で発行者によって早期に失効されることがあります。クライアントは、証明書が失効していないかを確認する必要があります。その方法として、認証局が提供する失効リスト(CRL)をダウンロードする方法や、オンライン証明書状態プロトコル(OCSP)を利用する方法があります。サーバー側でOCSPレスポンスを取得しておき、TLSハンドシェイクの一部としてクライアントに提供する OCSP Stapling は、クライアントのプライバシー保護やパフォーマンス向上に役立ちます。curlの
-v
出力にはOCSP Staplingに関する情報が含まれることがあります。
- 証明書が有効期間内であっても、秘密鍵の漏洩などの理由で発行者によって早期に失効されることがあります。クライアントは、証明書が失効していないかを確認する必要があります。その方法として、認証局が提供する失効リスト(CRL)をダウンロードする方法や、オンライン証明書状態プロトコル(OCSP)を利用する方法があります。サーバー側でOCSPレスポンスを取得しておき、TLSハンドシェイクの一部としてクライアントに提供する OCSP Stapling は、クライアントのプライバシー保護やパフォーマンス向上に役立ちます。curlの
- 混在コンテンツ (Mixed Content):
- HTTPSで配信されているウェブページの中に、画像やスクリプト、CSSなどのリソースがHTTPで読み込まれている状態を「混在コンテンツ」と呼びます。このようなページは、ページ自体はHTTPSで保護されていても、HTTPで読み込まれたリソースが盗聴や改ざんの対象となる可能性があるため、完全に安全とは言えません。ブラウザは混在コンテンツを検知すると警告を表示したり、HTTPで読み込まれるアクティブなコンテンツ(スクリプトなど)の読み込みをブロックしたりします。curlはこのような混在コンテンツを自動的に検知して警告を出す機能は持っていませんが、HTMLコンテンツをダウンロードした後に、その内容を解析してHTTPで読み込まれているURLがないかチェックすることで、間接的に混在コンテンツの問題を確認できます。
これらのセキュリティ設定はサーバー側で行われるものですが、curlを使うことでクライアント側から接続先のサーバーがどのような設定で動作しているのかを詳細に調査し、その安全性を評価する手がかりを得ることができます。
まとめ
この記事では、curlコマンドを使ってHTTPSの基本的な仕組みを理解し、実践的に学ぶ方法を解説しました。
まず、HTTPの平文通信やなりすましといった課題を確認し、なぜHTTPSが通信の暗号化、認証、完全性を保証するために重要なのかを説明しました。次に、HTTPSの中核をなすSSL/TLSプロトコルの役割、TLSハンドシェイクの概要、共通鍵/公開鍵暗号の組み合わせ、そしてデジタル証明書と認証局の仕組みについて概観しました。
そして、本題であるcurlコマンドを使った実践に入りました。
-v
オプションを使うことで、普段は見えないTLSハンドシェイクのステップや、確立されたTLSバージョン、使用される暗号スイート、そしてサーバー証明書の詳細情報を確認できることを学びました。特に、証明書のSubject/SANとホスト名の一致確認、有効期間、発行者(CA)といった検証プロセスを-v
の出力から読み解く方法を詳しく解説しました。- 証明書検証がどのように行われるかを知るために、検証エラーが発生するケースとそのエラーメッセージを確認しました。また、検証を無効にする
-k
オプションの危険性を理解しました。 - 特定のCA証明書やクライアント証明書を指定して接続する方法についても触れました。
- HSTSヘッダーや、HTTPからHTTPSへのリダイレクト(
-L
オプション)の挙動を確認する方法も紹介しました。
これらのcurlコマンドの活用を通じて、HTTPS通信が単なるURLの https://
やブラウザの鍵マークだけでなく、その裏側で複雑かつ精密なセキュリティメカニズムが動作していることを実感できたのではないでしょうか。
HTTPSはインターネットの安全性を支える基盤技術であり、その仕組みを理解することは、ウェブサービスを開発・運用する側にとっても、エンドユーザーとして安全に利用する側にとっても非常に重要です。curlは、このHTTPSの世界を「覗き見る」ための強力なツールとなります。
この記事で紹介した内容はHTTPSとcurlの機能のほんの一部ですが、ここからさらに深く学ぶための良い出発点となるはずです。ぜひ、様々なウェブサイトに対してcurlで -v
オプションを試してみてください。サイトごとに異なる証明書情報や暗号スイートが使われていることに気づくでしょう。また、manページやオンラインドキュメントを参照して、curlの他の様々なオプション(例: プロキシ設定、タイムアウト設定、HTTP/2の利用など)についても学んでみてください。
インターネットは常に進化しており、セキュリティ脅威も変化し続けます。HTTPSの理解を深め、安全な通信を実現・維持していくための継続的な学習が重要です。