OpenSSLの脆弱性で想定されるリスク

JVNJPCERT/CCの記事があまりにもさらっと書かれていて、具体的なリスクが想像しづらいと思うので説明します。

今北産業 (今ニュース見て来たから三行で教えて欲しいという人向けのまとめ)

  1. インターネット上の「暗号化」に使われているOpenSSLというソフトウェアが2年間壊れていました。
  2. このソフトウェアは便利なので、FacebookだとかYouTubeだとか、あちこちのウェブサイトで使っていました。
  3. 他の人の入力した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処理が終わり復号された平文の通信内容もふくまれるため、以下のような攻撃が成立します。

過去の通信内容を盗聴されてしまう

特に意識せず設定されたSSLサーバの場合、SSL証明書秘密鍵を知っている攻撃者は、暗号化されているはずの通信内容を復号して、内容を見ることができます。

特に、毎年SSL証明書を更新する毎に秘密鍵を作り直していなかった場合、過去の通信内容を保存している組織*3があった場合、過去に遡って全ての通信内容を復号して、そのなかのあらゆる情報を知ることができます。たとえ毎年秘密鍵を生成し直していた場合でも、直近の最大1年間の通信内容は全て筒抜けです。

これに対しては、Forward Secrecyという対策が存在します。

ただし、これまで必要性が重要視されなかった(まさかこれほど大規模に秘密鍵が漏洩する脆弱性が見つかるなんて思われていなかった)、性能が従来のRSAより若干遅い、などの理由があってあまり普及していません。今回を良い機会として、利用している暗号化アルゴリズムを見直し、Forward Secrecyを有効にするのが良いでしょう。Verisignから証明書ビジネスを引き継いだSymantecは以下のように主張しています。

結論として、ウェブサイトが RSA から離れて Forward Secrecy を提供するとともに、極めて低速なDHEよりもECDHE 鍵交換を配備することを、我々は強く推奨します。

誰かに偽のSSLサーバを立てられてしまう

たとえば、sns.example.jp というSNSSSL証明書秘密鍵が漏洩したとします。攻撃者はすかさず、その秘密鍵を使って、sns.example.jp の正当なSSL証明書を持った偽サーバを公開できます。公衆Wifiを使っていたり、DNSへの攻撃を併用すれば、その偽サーバにアクセスさせることができます。

アドレスバーを見ろと言ったところで正しいドメインで鍵が表示されているわけですし、たとえEV-SSL証明書を使ってアドレスバーを緑に染め上げていたとしても、全く同じ証明書でサーバを用意されてしまっては無力です。

これが、脆弱性のあるバージョンを使っていた場合に証明書の再発行だけでなく、「失効」が必要となる理由です。

ApacheやnginxでSSLを提供し、脆弱性があった場合 (APサーバ併用)

アプリケーションサーバの前段にApacheやnginxを設置し、そこでSSL処理を行っていた場合です。

ロードバランサーの場合に加えて、以下の情報が漏洩します。

  • httpd.confや.htaccessで設定されている内容の全て
  • Apacheが読み取っていたhtpasswdファイルの内容

ApacheSSLを提供し、脆弱性があった場合 (mod_php5,mod_perl等)

mod_php5やmod_perlなどを利用し、Apacheモジュールとしてウェブアプリケーションを動かしていた場合です。

これまで登場した全ての内容に加えて、以下の内容が漏洩します。

  • 全てのアプリケーションコード
  • 全てのアプリケーション設定
    • データベース等の接続先、ユーザ名、パスワード
    • TwitterFacebook等のconsumer_secret
    • Rails等のCookieベースセッションの暗号化キー(secret_token, secret_key_base)
  • DB等から取得したメモリ上のデータ全般(別リクエストの内容も、場合によって空きメモリに残っている可能性がある)

ここまでくると、想定されるリスクはかなり大きいです。

  • 別ユーザからのリクエストに含まれた、パスワードや個人情報、クレジットカード番号、セキュリティコードなどが空きメモリに残っていた場合、それが漏洩します。
  • Cookieベースセッションは、自由にセッションデータの捏造ができます。
  • インターネットからDBサーバ等に直接接続ができなくとも、別の攻撃を行うための予備情報を攻撃者に与えることになります。

PHPであっても、PHP-FPMを使うなどApacheとプロセスを分けることで、権限ごと分離できるので、今回を期に挑戦すると良いのでは無いでしょうか*4

外部のサーバ等にSSL通信を行っている場合

SSH系を除くほぼ全てのクライアントアプリケーションの暗号化通信が当てはまりますし、サーバ側であっても、外部のAPIサーバへの通信などにはあてはまります。

あくまでこの場合、攻撃者が用意したサーバに接続しない限り安全であると考えられますが、その一方で、DNSキャッシュポイズニングBGPのハイジャックなど、攻撃する側がトラフィックを呼び込むための手法が存在しています。

これをされた場合、そのクライアントが持っている接続先リストやそこに含まれるユーザー・パスワードが漏洩します。

外部に接続するサーバ側アプリであれば、前述の「ApacheSSLを提供し、脆弱性があった場合 (mod_php5,mod_perl等)」と同等です。例えばSSLサーバとしては社内からの接続しか受けていなかったとしても、抜け道があるので、やはり上げておきましょう、ということです。

まとめ

  • 脆弱性の影響を受けていたら、証明書の「失効」までが必要です。
  • Forward Secrecy が無ければ、秘密鍵の漏洩が通信内容の漏洩に直結します。
  • SSL処理とアプリケーションコードはプロセスを分けよう。

補足情報

あまりにも再現が容易であることから、既に脆弱なサーバの探索が増えているようです。

警察庁の定点観測システムにおいても、9日以降、当該攻撃コードに実装されている
Client Hello パケットと、完全に一致するパケットを多数観測しています。このことから、同攻撃コードを使用して、脆弱性が存在するサーバ等の探索が実施されているものと考えられます。

*1:2012年2月にRFC6520として公開され、PMTU discoveryなどを想定しているようです。

*2:なお、RFC6520としては、ハンドシェーク中のHeartbeatRequestは捨てるべき(SHOULD)となっています。

*3:某国のNなんちゃらとか

*4:実際、OpenSSHにはそうやって権限分離が実装されたという歴史があります。