WebSocketのマスキングキーは何のために存在しているのか調べた

  • 21
    Like
  • 0
    Comment
More than 1 year has passed since last update.

WebSocketのマスキングキーは何のために存在しているのか調べた

WebSocketの仕様を読んでいると、フレーム中に"マスキングキー"というよく分からない値を見つけました。

http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html#section-5.2

何やらこれを元にデータを変換しているようですが、用途がどうにも解せません。
マスキングキー自体が送信するデータに含まれているため、データの内容自体を保護するためのものではなさそうです。

読み進めるとマスキングキーについてもうちょっと詳しい解説が載っていました。

http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html#section-10.3

なるほど、キャッシュ汚染攻撃というやつへの対策でしょうか。google先生に聞いてみると、こんな記事が出てきました。

WebSocketにセキュリティの懸念。Firefox 4とOperaで機能を無効化へ
Firefoxの4 WebSocketsのサポート無効化関連

Google groupsでのやりとりが非常にわかりやすいです。
つまり、流れるデータをWebSocket上で行われているものと認識せず、しかもそれをHTTPリクエストとして解釈する、お茶目なプロキシサーバが世の中には存在するってことですね。その結果意図しないデータをキャッシュしてしまう場合がある、というもののようです。

どう問題なのか

ちょっとコードを書いて整理してみます。
問題になるケースでは、まずユーザーは攻撃者が管理するサーバーを訪れる必要があります。
そのサーバー(ここではattacker.comにしておきます)には、次のようなスクリプトを用意しておきます。

var ws = new WebSocket( 'ws://attacker.com' );

ws.onopen = function( ) {
   ws.send( "GET /ga.js HTTP/1.1\r\nHost: http://www.google-analytics.com\r\n\r\n" );
};

このスクリプトでは、読み込まれた際にWebSocketの接続を確立します。攻撃者のサーバーでは、このリクエストをWebSocketのプロトコルに則り正常に処理します。
接続が確立したら、クライアントから一見HTTPのGETリクエストにも見えるような文字列を送信します。

調べたところによると、ごく一部のお茶目なプロキシサーバはこのHostを含む送信内容を見た後、これはwww.google-analytics.comに対して行われている接続であるものとしてキャッシュを行ってしまうことが問題のようです。

さて、クライアントからデータを受け取ったWebSocketサーバは攻撃者が用意したものですから、クライアントから送られてきた擬似HTTPリクエストを確認したあと、任意のデータを返すことができます。
もちろん、WebSocketで規程されたプロトコルに従う必要もないため、ここで、HTTPレスポンスとして正常なデータを返すこともできます。例えばこんなデータですね。(日付とかは適当です)

HTTP/1.1 200 OK
Expires: Sat, 22 Feb 2030 00:00:00 GMT
Last-Modified: Fri, 24 Jan 2014 00:00:00 GMT
Cache-Control: public
Connection: close

Evil Data!!!

めでたしめでたし、これで任意のデータをプロキシサーバにキャッシュさせることが出来ました。
これでこのプロキシサーバを利用して http://www.google-analytics.com/ga.js を取得しようとすればキャッシュに乗ったこのデータが返される、というわけですね。

そこでマスキングキー

つまり、攻撃者の意図したデータがそのまま通信経路上を流れてしまう、というのが問題というわけですね。
そしてこの問題への対策がマスキングキーというわけです。

マスキングキーは予測不能な32bitの値でなければならず、クライアント側はデータ送信前にマスキングキーを用いてデータをXOR演算でごにょごにょする必要があります。
当然ですが、スクリプト上からマスキングキーを任意の値に設定することは出来ません。

マスキングキーが予測不能であるため、攻撃者が意図したバイト列を通信経路上に流すことが出来なくなります。
もちろん、攻撃者のサーバにはマスキングキーが送信されるため、擬似HTTPリクエストを受けとることは出来ますが、重要なのはプロキシサーバにHTTPリクエストだと誤認させることですから、それが出来たところで何の意味もない、というわけですね。