はじめに
この文章は自分の利用するWebサーバでHTTPS通信を初めて使うユーザのために、HTTPSの概念を簡潔に説明する文章です。一部の記載は仕様を元に丸めて説明しているので、実際の利用にあたっては個別に調査をお願いします。
1. HTTPとその課題
HTTP(Hyper Text Transport Portcol)※詳細はリンク先を見てね1はインターネットのアプリケーションレイヤの標準のプロトコルで、The Internetの黎明期から現在に至るまで利用されています。
当初の「公開された情報を共有」するという目的を果たすためにHTTPは必要にして十分な機能を備えていました。(1990年代)
The Intenet≒Webの力が世界中に認知され、利用者の増加や利用方法の多彩化など「つながる世界」が広がるにつれ、HTTPでは不都合なことが起きてきました。もともとHTTPは「公開された情報を共有」することを目的としていたのに、あまりに便利すぎて「違う目的」に利用が広がっていったのです。
- 各種電子申請
- 旅行やECなど「決済」を伴う商行為
- 秘匿性の高い情報のセマンティックな共有
といった、「利用スコープの限られた」情報のやり取りをWebを介して行う必要が出て来たのです。HTTPは「共有」を前提としているため、「隠したい」という欲求に対しては少し弱いのです。当時のマシンパワーやネットワークリソースの貧弱さも背景のひとつです。
致命的な弱点は次の3点です。
- 経路中のどのノードでも情報を垣間見ることができる
- HTTP通信では情報を「平文」のテキストで流しているので、盗聴されてしまうと完全に無防備
- 通信相手を特定することができない
大きな問題は2点目と3点目です。一見暗号化技術で2点目だけを手当すれば問題ないように思えますが、「通信相手が本物かどうかわからない」というのは中間者(Man in the Middle )攻撃に弱く、通信相手を間違えるとせっかく暗号化しても復号され意味がなくなるからです。
ユースケースで考えてみよう
ネットバンキングサービスで銀行にA社への送金指示をする場合を考えてみます、実際には幾重にも防御が張られているので、こんなことはないんですが。まぁ思考実験だと思ってお付き合いください。(MFAがどうたらとか、認可時に認証が・・・とかそういう話は受け付けないっていう宣言です。)
前提事項
- サービス利用者はユーザーIDとパスワードを使った認証を行う
- 送金前にユーザーIDとパスワードを使った認証を伴う認可行為を行う
- 認証後、認証済みであることを示す印=クレデンシャルを取り交わし、このクレデンシャルを保持していること認証済みの証として扱う。
- 利用するプロトコルはHTTPとして、経路上は平文で流れており、攻撃者はこれを盗聴できる。
「認証も認可もおこなわれていて、それなりにちゃんとやっているじゃん」確かにそうなんです。が、通信がざるだとアプリケーションレイヤでの工夫なんて全部ぶっとびます。
平文で流れている場合の問題
まずはHTTPで「平文2」でやり取りしているケースです。
前提で、ID/passwordによるシステム利用時の認証があるので、OKに見えますよね。この時、盗聴されると「成りすまされる3」のは
- ID/Password
- クレデンシャル
ですよね。ID/Passwordの送信はログイン時の一度。クレデンシャルは以降のやり取りで取得されていしまいます。
1の場合も2の場合も、 パスワードが変更されるまでもしくは利用者がログアウトするまでは攻撃者は成りすますことが可能なわけです。私が攻撃者ならこの「ゴールデンタイム」にpasswordを変更して、正規の利用者が何もできないようにしてしまいます。 そしたらあとは好き放題ですよね。
さて、ではサービスの認証ではなく送金前の「認可」ならどうでしょか結論から言えば、変わりありません。ID/PASSWORDがあらかじめ抜かれているなら、このタイミングで盗聴する必要すらありません(盗聴したID/PASSWORDを利用して認可すればいいのです)し、このタイミングで抜かれても結果は変わりません。 あらかじめクレデンシャルが抜かれているケースではID/PASSWORDは手元にありませんが。認証情報を変更してしまえば自由にふるまえます。
少なくとも、この段階でのID/PASSWORDの確認は盗聴リスクを上げているだけ ということですね。そのため多くの銀行は2000年代に「第二パスワード」もしくは「鍵表」を配布して、サービス認証と認可時の認証を分けて管理していたわけです。
通信内容を暗号化しただけでは解決しない問題
さて、通信を平文で行うことの危なさがわかったかと思います。では「通信文を平文から暗号文」に変更したらどうでしょうか。万全でしょうか?答えは残念ながら「否」です。
え?なんで?暗号ってそんなに簡単に復号できるの?
出来ません。少なくともBase64を「暗号」といっているようなあほなことをしていない限り、「鍵」をもっていない暗号文を復号することはそう簡単にはできません。
ではなぜ、危険なのでしょうか?それは
暗号文は相手が正しいこと担保してくれない からです。
他の誰からも見れない暗号文。でもその通信相手が「攻撃者」だったらどうでしょう?これはもう一大事。あなたが暗号文を使って安心しておしゃべりしてた相手は、攻撃者だったわけです。IDだってPASSWORDだって、全部知られてしまいます。
「わざわざ攻撃者を間にいれるあほはいない。」 そういう人もいるかもしれません。
- DNSが攻撃をうけて名前解決が変更されている場合
- メールによってあたかも正規のサイトであるかのように誘導する場合
- 検索結果の上位に表示させて誘導する。
こんな攻撃をされると中間者を間に入れてしまう危険があります。そこで、「接続している相手」が、本当に意図したサーバなのかを確認する術が必要です。
さて、ここまでの課題を整理すると。HTTPには次の機能が必要だということになります。
- ブラウザとサーバ間の通信内容の暗合化
- 接続先サーバの身元確認
さて、この時暗号化アルゴリズムは「共通鍵暗号」にします。なぜなら公開鍵暗号は便利ですが、復号が大変重い処理でサーバー側/クライアント側双方でそれなりに時間を必要してしまうからです。しかし、その場合「鍵配送問題」が付きまといます。そこで、鍵交換のために「公開鍵暗合」を利用しましょう。これにより、サーバとブラウザはあらかじめ鍵を交換しておく必要なく、安全に鍵を配送することができるようになります。通信を暗号化しようとするとき
- 全体の暗号化は共通鍵暗号で
- 共通鍵を交換するときは公開鍵暗号で
というのはよく選択される方式なので、アイデアとして理解しておきましょう。
最終的に大きな改善点は以下の通りです。
- HTTP電文全体を共通鍵で暗号化する(共通鍵暗号)
- 接続先サーバの身元を保証する(電子署名)
- 共通鍵を安全に交換する(公開鍵暗号)
これにより「通信の秘匿性」を高めて安全な通信が実現されるわけです。
2. HTTP over SSL/TLSでの解決
さて、世の中にはすでに「HTTP」という確立したテキストベースの通信方法が存在しています。でも。ここには前述の課題があるわけす。
この課題を解決する場合にとれる方法ってなんでしょうか?
- 新たにシン・HTTPを設計・実装する
- HTTPを拡張するために拡張レイヤを追加する
多くの場合、2.を選択します。ほんとに多くの場合です。そのため、コンピュータの世界はミルフィーユ上にレイヤーが分割され、あらゆる機能が実装されているわけです。この話題はいずれどこかでやります。
1.を選択するメリットは、「過去資産の制限を受けない」この1点につきます。ほんとこれだけ。この効果は「昔の遅い設計を使わなくていいから、高速化などの恩恵が受けらられる」などですが。デメリットが大きすぎます。デメリットは2のメリットの裏返しなので明記は避けます。
2.を選択するメリットは「現在の資産をそのまま利用可能」であるという点ですその効果は
- すでに存在する処理を再設計実装を行う必要がない
- だからお金がかからない
- だから時間がかからない
- だから余計な問題を引かない
しかも、これは「ブラウザ・サーバ」の両方で恩恵を受けるのです。逆に言うと1は高速に「なるかもしれない」けど、金も時間もかかって、従来安定稼働していた処理さえもあらたに不具合を抱えてしまう危険まであるという、ちょっとナンセンスな選択になります。HTTPは、前述の課題にSSL/TLSというレイヤを追加することで問題の解決を図りました。3
なお、図ではSSL/TLSプロセッサとしています。実際SSL実現初期のころは独立したH.W.が配置されていたのです。(それだけ重い処理なのです)
3. 認証局の果たす役割
認証局はサーバの公開鍵に電子署名を施し、証明書を発行する機関です。つまり、サーバの身元を保証する身元引受人の役割を果たします。仮にCAが身元を保証しない場合、ブラウザはサーバに対してアクセスしません。
身元の不確かな相手に接続するのはそれだけでリスクだからです。ではCAが身元を保証する場合はどうでしょう。
この様に、事前に信用しているCAの紹介であることから、安心して接続を開始します。サーバの信用を、CAが肩代わりするのです。
サーバー証明書認証を利用する場合、サーバーはCAから自分の扱う公開鍵に電子署名してもらい、その事実を示す証明書を取得する必要があります。
証明書発行のフローは以下の通りです。
WebServerの作業
- 通信に使う非対称暗号化の公開鍵と秘密鍵(=キーペア)を生成
- 公開鍵をもとにCSR(=Certificate Signing Request)を生成する。これは、CAに対して、この共通鍵に署名して。僕の身元を保証してね。という依頼書であり。署名対象の共通鍵も内包している。
- CSRをCAに提出して、身元保証を依頼する。
CAの作業
- 提出されたCSRを一覧に登録する
- 登録したCSRに対して署名を施し、サーバ証明書を発行する
- Userに対して、CAの証明書を発行する。(ここにはCAの公開鍵が内包されている)
利用者の作業
- CAから提供された証明書を、自分のコンピュータもしくはブラウザに登録する。
4. 証明書を使った接続先の担保
さてこの仕掛けで何ができるんでしょう。端的にいうと以下の図のようなやり取りをへて、「接続先」が安全かどうかを確認しているのです。
- CA夫は予め自らの公開鍵(CA公開鍵)を含んだ証明書をブラウザ美に渡しておきます
- ブラウザ美はサーバ男への接続時に、誰があなたを紹介してくれてるの?と紹介状=サーバー証明書を要求します
- サーバー男はブラウザ美に「CA夫さんの紹介です」と紹介状=サーバー証明書を提供します。なお、この証明書にはサーバー男の公開鍵(サーバー公開鍵)がCA秘密鍵で暗号化されて格納されています。
- ブラウザ美はCA公開鍵を利用してサーバー証明書のデータが復号できるか試行。鍵が外れれば、偽の紹介状じゃないとわかるので通信を続行します。
- ブラウザ美はこの時取り出したサーバー公開鍵を利用して以後のサーバー男とのやり取りに使います。
なお、このCAを使った仕掛けは「CA」が身元を保証していることを前提に、WebServerの宛先が正しいことを担保します。つまりCAが信用できることが大前提の仕掛けです。そのため、信用できないCA証明書を受け入れてしまうと、仕掛けそのものが崩壊します。
6. まとめ
長くなりました。そろそろ疲れてきたのでまとめを。。。
- HTTPでは、アプリケーションでどんな仕掛けを作っても、盗聴されたら終わりだよ
- 盗聴に備えて、通信を暗号化する必要があるよ。
- 暗号化してても、接続先を間違えたら危ないよ
- 接続先の担保はCA認証局を利用した独自のプロトコルで実現するよ。
- これらのことをSSL/TLSレイヤで実装し、実現しているよ。
次回は、いよいよ。認証局を設定して、TLS通信ができる状態にまで持っていきます。お楽しみに。
-
時々Base64とかBase64+スクランブルを暗号化とか言っちゃうひともいるんですけど、ここではこういうのも全部「平文」として扱います。鍵も何にもなく復号できちゃう暗号って何なんでしょうね ↩