JVNやJPCERT/CCの記事があまりにもさらっと書かれていて、具体的なリスクが想像しづらいと思うので説明します。
今北産業 (今ニュース見て来たから三行で教えて欲しいという人向けのまとめ)
- インターネット上の「暗号化」に使われているOpenSSLというソフトウェアが2年間壊れていました。
- このソフトウェアは便利なので、FacebookだとかYouTubeだとか、あちこちのウェブサイトで使っていました。
- 他の人の入力したIDとかパスワードとかクレカ番号とかを、悪い人が見ることができてしまいます。(実際に漏れてる例)
他にも色々漏れてますが、とりあえずエンジニア以外の人が覚えておくべきはここまででOKです。もう少し分かりやすい情報が以下にあります。
まだ直っていないウェブサイトもあれば、元々壊れていないウェブサイトもあるので、「直したからパスワード変更してね」って言ってきたら変更してください。あと、悪い人が偽メール送ってきているので、メールで連絡してきたとしても、ブラウザのブックマークから開きましょう。
ここからはエンジニア向けの詳細です。
今回の脆弱性の内容
いわゆる「SSL通信」と呼ばれる暗号化通信は、実際にはSSL 3.0とより新しいTLS 1.0〜1.2(互換性のためプロトコル上の番号は3.1〜3.3)というプロトコルで定義されています。これらを使うために、様々なソフトウェアが利用している共通ライブラリが OpenSSL です。今回の脆弱性は、このTLS 1.2に追加されたハートビート拡張*1の実装の不具合によるものです。
SSL通信の最初「ハンドシェーク」段階でSSL証明書の検証などを行いますが、今回の脆弱性はそのハンドシェーク段階の中でも発生する*2ため、正しいSSL証明書を持っていなくても攻撃が成立します。ほとんどの場合にログが残らないのもこのためです。
攻撃者は、通信の相手のメモリ内容を取得することができます。一回で最大64キロバイト、同じプロセス内の情報に限られますが、ログに残らず、めぼしい情報が取得できるまで何度でも繰り返すことができるため(これがメモリガチャと呼ばれる理由)、プロセス内の全ての情報が漏洩したと考えるべきです。
「同じプロセス」というところが問題で、どのプロセスがSSL通信をしたかによってリスクが大きく変わります。
ロードバランサーでSSLを提供し、脆弱性があった場合
ロードバランサーはSSLのサーバ側として、SSL証明書の秘密鍵をメモリ内に保持します。この秘密鍵が攻撃者に漏洩します。
SSL処理をしているところでデータが漏洩した場合のリスクは、大きく三つあります。
(これは、Apache等でSSL処理をしている場合も同様です!)
すぐ直前の通信内容を盗聴されてしまう
空きメモリ内には、直前の通信内容がクリアされず残っている場合があります。SSL処理が終わり復号された平文の通信内容もふくまれるため、以下のような攻撃が成立します。
- 別のユーザに表示された、あるいは入力した個人情報が漏洩する
- 別のユーザのセッションIDを入手して、ログイン中の第三者になりすます
過去の通信内容を盗聴されてしまう
特に意識せず設定されたSSLサーバの場合、SSL証明書の秘密鍵を知っている攻撃者は、暗号化されているはずの通信内容を復号して、内容を見ることができます。
特に、毎年SSL証明書を更新する毎に秘密鍵を作り直していなかった場合、過去の通信内容を保存している組織*3があった場合、過去に遡って全ての通信内容を復号して、そのなかのあらゆる情報を知ることができます。たとえ毎年秘密鍵を生成し直していた場合でも、直近の最大1年間の通信内容は全て筒抜けです。
これに対しては、Forward Secrecyという対策が存在します。
- Twitter、暗号解読を困難にする「Perfect Forward Secrecy」を導入 (2013/11/25)
ただし、これまで必要性が重要視されなかった(まさかこれほど大規模に秘密鍵が漏洩する脆弱性が見つかるなんて思われていなかった)、性能が従来のRSAより若干遅い、などの理由があってあまり普及していません。今回を良い機会として、利用している暗号化アルゴリズムを見直し、Forward Secrecyを有効にするのが良いでしょう。Verisignから証明書ビジネスを引き継いだSymantecは以下のように主張しています。
結論として、ウェブサイトが RSA から離れて Forward Secrecy を提供するとともに、極めて低速なDHEよりもECDHE 鍵交換を配備することを、我々は強く推奨します。
誰かに偽のSSLサーバを立てられてしまう
たとえば、sns.example.jp というSNSのSSL証明書秘密鍵が漏洩したとします。攻撃者はすかさず、その秘密鍵を使って、sns.example.jp の正当なSSL証明書を持った偽サーバを公開できます。公衆Wifiを使っていたり、DNSへの攻撃を併用すれば、その偽サーバにアクセスさせることができます。
アドレスバーを見ろと言ったところで正しいドメインで鍵が表示されているわけですし、たとえEV-SSL証明書を使ってアドレスバーを緑に染め上げていたとしても、全く同じ証明書でサーバを用意されてしまっては無力です。
これが、脆弱性のあるバージョンを使っていた場合に証明書の再発行だけでなく、「失効」が必要となる理由です。
ApacheやnginxでSSLを提供し、脆弱性があった場合 (APサーバ併用)
アプリケーションサーバの前段にApacheやnginxを設置し、そこでSSL処理を行っていた場合です。
ロードバランサーの場合に加えて、以下の情報が漏洩します。
ApacheでSSLを提供し、脆弱性があった場合 (mod_php5,mod_perl等)
mod_php5やmod_perlなどを利用し、Apacheモジュールとしてウェブアプリケーションを動かしていた場合です。
これまで登場した全ての内容に加えて、以下の内容が漏洩します。
- 全てのアプリケーションコード
- 全てのアプリケーション設定
- DB等から取得したメモリ上のデータ全般(別リクエストの内容も、場合によって空きメモリに残っている可能性がある)
ここまでくると、想定されるリスクはかなり大きいです。
- 別ユーザからのリクエストに含まれた、パスワードや個人情報、クレジットカード番号、セキュリティコードなどが空きメモリに残っていた場合、それが漏洩します。
- Cookieベースセッションは、自由にセッションデータの捏造ができます。
- インターネットからDBサーバ等に直接接続ができなくとも、別の攻撃を行うための予備情報を攻撃者に与えることになります。
PHPであっても、PHP-FPMを使うなどApacheとプロセスを分けることで、権限ごと分離できるので、今回を期に挑戦すると良いのでは無いでしょうか*4。
外部のサーバ等にSSL通信を行っている場合
SSH系を除くほぼ全てのクライアントアプリケーションの暗号化通信が当てはまりますし、サーバ側であっても、外部のAPIサーバへの通信などにはあてはまります。
あくまでこの場合、攻撃者が用意したサーバに接続しない限り安全であると考えられますが、その一方で、DNSキャッシュポイズニングやBGPのハイジャックなど、攻撃する側がトラフィックを呼び込むための手法が存在しています。
これをされた場合、そのクライアントが持っている接続先リストやそこに含まれるユーザー・パスワードが漏洩します。
外部に接続するサーバ側アプリであれば、前述の「ApacheでSSLを提供し、脆弱性があった場合 (mod_php5,mod_perl等)」と同等です。例えばSSLサーバとしては社内からの接続しか受けていなかったとしても、抜け道があるので、やはり上げておきましょう、ということです。