81.補足事項(1) … "OpenSSL"の脆弱性問題「Heartbleed Bug」の詳細


◆ 北米時間の2014年4月7日、"OpenSSL"に世界中のIT関係者を震撼させるような脆弱性問題が存在していた事が発覚した。

http://www.itmedia.co.jp/enterprise/articles/1404/09/news041.html

http://heartbleed.com/

本項では、この脆弱性問題「Heartbleed Bug」について、これを技術的な視点で以下に解説する。

◆ 問題の箇所はTLS/DTLSの「Heartbeat拡張」の実装部分で、具体的にはHeartbeatのリクエスト文に対するレスポンス応答文の作成・編集の処理部分に重大な実装ミスが見つかった。

https://github.com/openssl/openssl/commit/96db9023b881d7cd9f379b0c154650d6c108e9a3

リクエスト文およびレスポンス文のフォーマットを簡略化して説明すると、これらは共に、先頭1バイトが電文の種別("Type")、続く2バイトがデータ本体部分の長さ("Length")、4バイト目以降がデータ本体("Data")という構造になっている。

 
 
    ┌──┬───┬────────────────┐
    │Type│Length│Data              │
    └──┴───┴────────────────┘
 
 

レスポンス応答の処理フロー自体は非常に単純なもので、受け取ったリクエスト文の先頭の"Type"項目(電文種別)の内容を、"TLS1_HB_RESPONSE"のマクロ名で定義(#define)されるタイプ番号(定数)で書き換えてからそのまま送信元に送り返すというものだ。

レスポンス文を作成・編集する処理は、メモリ上にレスポンス文の作成・編集用の領域を別途新たに確保(malloc)して、その先頭部分の"Type"部分に"TLS1_HB_RESPONSE"を設定し、続く2バイトの"Length"部分には受信したリクエスト文の"Length"部分の内容をそのまま設定し、そして、4バイト目以降の"Data"部分は受信したリクエスト文が置かれているメモリ領域からその"Data"部分をコピー(memcpy)するという形で処理されていた。

 
 
            <---------------@--------------->
    ┌──┬─A─┬────────────────┐
Request │Type│Length│Data              │
    └──┴───┴────────────────┘
            ↓↓↓↓↓↓↓memcpy↓↓↓↓↓↓↓
    ┌──┬───┬────────────────┐
Response│Type│Length│Data              │
    └──┴───┴────────────────┘
 
 

しかし、その"Data"部分のコピー処理の際、受け取ったリクエスト文の"Data"部分の「実際の長さ」(上図@)を元にしてコピーする長さを決定するのではなく、リクエスト文の"Length"項目(上図A)に設定されていた値をチェックせずに盲目的に正しいと信じて、その値でコピーする長さを決定してしまうという、いわゆる"read overrun"に該当するロジックミスがあった事が発覚した。

◆ この場合、もし仮にそのリクエスト文の"Length"項目(下図@)に、実際の"Data"部分の長さ(下図A)よりも遥かに大きい値(下図B)が設定されていた場合には、コピー元のリクエスト文が置かれたメモリ領域より後ろの部分(下図C)の「本来読み取るべきでないメモリ領域」の内容まで読み取られ、その内容がレスポンス文として編集されて(下図D)、ネットワークを通じて外部に送り出されることになってしまう。

 
 
            <----------------------------B---------------------------->
    ┌──┬─@─┬─────┐───────────────────────┐
Request │Type│Length│Data   │           C           │
    └──┴───┴─────┘───────────────────────┘
            <----A---->            ↓
    ┌──┬───┬─────┬───────────────────────┐
Response│Type│Length│Data   │           D           │
    └──┴───┴─────┴───────────────────────┘
 
 

これはつまり、その「本来読み取るべきでないメモリ領域」(上図C)に、秘密鍵や送受信データ(SSL処理が終わった復号済みの平文)といったようなデータが置かれていた場合、メモリ上のそれらのデータをネットワークを経由して読み取ることができるという事であり、実際、ある調査会社が行った実験では、X.509の公開鍵証明書、ユーザーネームとパスワード、インスタントメッセージ、メールや重要書類などにアクセスするためのキーを盗むことなどに成功し、しかも、攻撃の後には盗んだ痕跡が一切残らなかったという。

◆ なお、リクエスト文の"Length"項目は、2バイトの"unsigned int"属性ゆえ、0xffff = 64(kbyte) が一回の攻撃で読み取れる最大のデータ量となるが、しかし、ハッキングの痕跡が一切残らず攻撃者は長期間に渡って何度でもハッキングを試みる事ができるので、漏洩する情報量は計り知れないほどの量になる恐れがある。

しかも、そもそも攻撃者が「秘密鍵」を入手する事ができたとすれば、そのサイトの全ての通信内容を「丸裸」にすることができてしまう。

そのサイトの通信パケットを傍受して、SSLハンドシェイク段階のパケットを手元の秘密鍵で復号化して共通鍵を入手し、ハンドシェイク後のメインの通信もその共通鍵を使って片っ端からパケットを復号化して通信内容を「丸裸」にしてやれば、例えば一般の利用者がサイトにログインする際に入力するIDやパスワードなどの情報を大量に収集できてしまうことになる訳で、その情報漏洩の規模は想像を絶するものとなる。

◆ この実装ミスについては最終的に、リクエスト文の"Data"部分の実際の長さが、その"Length"項目に設定された値と食い違う場合には、そのリクエストそのものを破棄するというロジックに改められる事となった。

「バグ」のレベルで言えば実に初歩的でありふれた「コーディングミス」と呼べるレベルのものであり、それゆえ「なぜ詳細設計やコーディングレビューの段階で気付かなかったのか」といったような批判も多いようだ。

しかし、設計の当事者以外の人間が後になってから「たら・れば」でアレコレと批判するのは簡単だ。

この手のミスはいくらコーディング規則やらレビューやテストを徹底したところで完全に駆逐出来ないという事もまた厳然たる「現実」なんであって、個人的には、今回の件については、たまたまその影響・被害が余りにも甚大すぎたという点で「不運だっただけだ」という気がしてならない。

◆ サーバー管理者側がこの問題に対して採るべき対策については既に多くのサイトで詳しく説明されているが、その一方で、「サイトの利用者の側が採るべき対策」として「大至急IDとパスワードを変更すべきだ」といったような提案をしているサイトを実に多く見かける。

しかし、上記の解説を読んで頂いても解ると思うが、対策の済んでいないサーバーに接続して、いくらIDやパスワードを変更する作業をしてみたところで、それらが再び盗まれてしまう可能性が高いわけであって、それが如何に「的外れ」な提案であるかがお解かり頂けると思う。

この脆弱性は2年前から存在してたとの事で、むしろ優先すべきは、過去2年間に問題のあるサイトにアクセスした経験がある場合は、そこでどういった情報を入力したのか(ID、パスワード、住所・氏名、クレジットカード番号etc…)を出来る限り思い出し、そして、それらの情報が漏れた場合に生じる恐れがある被害を想定して、至急にそれに対する対策を講じるという事の方である。

例えば、過去2年間に問題のあるサイトでクレジットカードを用いてオンラインショッピングなどをした覚えのあるような人は、その際にカード番号を盗まれている可能性がある訳で、もしもそのような事態が心配される場合には、過去2年間のカード利用の履歴の中に自分の身に覚えのない決済がないかどうかを確認し、不運にも不正利用が見つかった場合には、至急にカード会社に連絡して指示を仰ぐ等の処置が必要となる。

そして、問題のサイトに対して採るべき対策としては「とりあえずサーバー側の対策が終わるまでは何もしない」というのが正解という事になる。

この騒ぎに「便乗」して、パスワード変更の呼び掛けを装った詐欺メールや、偽の脆弱性チェックサイトへの誘導などの、別の攻撃の危険性が浮上しているとの情報(*1)もあるので、安易な行動に走るような事はせずに、まずは冷静になってから、正確な情報の収集と判断に努めるべきだ。

(*1) http://www.itmedia.co.jp/enterprise/articles/1404/11/news053.html