ページ

2012年1月18日

websocket client 0.5のリリース

ちまちま作っていたwebsocketのpythonのクライアントライブラリをアップデートしました。バージョンは0.5ですね。以前サポートしてたプロトコルのバージョンは、echo.websocket.orgで使えなくなってしまっていたので、古いプロトコルのコードはごっそり消しました。今回はRFC6455になったhybi13だけをサポートしています。いや、サポートしているつもり。

日本人が使っているって聞いたことないので、日本語でかいても無意味なような気もしますが・・・

テキスト転送だけじゃなく、バイナリデータの転送もできます。一つのデータを複数のフレームが分割して送受信できるみたいですが、それはまだ、対応していません。


2012年1月13日

rfcになったwebsocketのデータ転送の部分

前回の続きです。前回はハンドシェークまでだったので、今回はデータ転送の部分です。大昔のプロトコルはテキストの転送は0x00で始まって0xffで終わるって言う単純なモノだったので楽でした。その後、データの転送にABNFでframeをつかってヘッダー領域とデータ領域に分けられ、面倒になりました。と言うことで、今回はこのデータの転送のお話。

データ転送はframeでヘッダー部分とデータ部分に大別されます。
ヘッダー部分は最初の一バイト目にいろんなフラグとデータのタイプを設定します。
2バイト目がデータをマスクするのか?と言う情報とデータの長さの情報を設定します。データは最大64bitのintの長さまで設定できます。データの長さに応じて、2バイト目から最大4バイト消費されます。
その次のバイトからがデータになります。2バイト目でマスクを使用するように設定されていれば、マスクで使用する情報が4バイト分設定されて、その次のバイトからマスクされたデータがセットされます。マスクしない場合は、データ部に入るとすぐに実データがセットされます。

マスクって言うのは、データの各バイトをxorしているだけです。ハンドシェークのkeyとacceptは、途中におかしなプロキシがいた場合の単純な解決法だと好意的に解釈できんですが、このマスクはさらに意味不明です。ハンドシェークのときにマスクで使用するバイトを交換するなら分かるんですが、各データ転送フレームごとにマスクのキーを送るって意味不明です。例えるなら、共通鍵で暗号化したデータを共通鍵と一緒におくるようなもんです。解読すれば一瞬でデータが復元できます。何を守りたいのか分かりません。base64を暗号化って言っているようなモノです。

それぞれのバイトの各bitの説明をしようかと思ったけど、めんどいので今日はここまで。と言うか、最初のバイトの2バイト目から4バイト目までの意味もまだよく知らないんですが・・・

2012年1月6日

RFCになったwebsocketのハンドシェイクの部分

@t2y に「You've been writing only about cat, recently. I feel you are over.」っていわれちゃいました。そんなことではいけないと思い、それから最新のwebsocketに対応してくれ、ってリクエストが来ているwebscoketのpython clientもバージョンアップすべく、RFCになったほうを読んでいます。大きな処理の流れは、昔のwebsocketと大きくは違わないので割愛します。

まず、サーバに接続してリクエストを投げます。クライアントからのリクエストはこんな感じです。今回はecho.websocket.orgに対してリクエストを投げています。

GET / HTTP/1.1
Host: echo.websocket.org
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: c6b8hTg4EeGb2gQMztV1/g==
Origin: http://echo.websocket.org
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

websocketのサーバに接続するとき、Sec-WebSocket-KeyとHost, Origin以外のヘッダーはほぼ固定ですね。Sec-WebSocket-Keyだけがリクエストごと変更されます。まあ、同じでも問題ないんだけど。

Sec-WebSocket-Keyはuuidの16bitのバイト列をbase64エンコードしたもの、っていうことになっています。でも、サーバの実装は長さのチェックとかしていなさそうなので、何でもいいかも。

このリクエストに対してサーバは、
HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: Kxep+hNu9n51529fGidYu7a3wO0=
Server: Kaazing Gateway
Date: Fri, 06 Jan 2012 07:39:19 GMT

となります。echo.websocket.orgってKaazing Gateway使っているんですね。で、Sec-WebSocket-Acceptでちゃんとしたサーバかをチェックしていますが、以前にも書きましたが、これで何がセキュアになるのか、さっぱり分かりません。

Sec-WebSocket-Acceptは、Sec-WebSocket-Keyで送った文字列に258EAFA5-E914-47DA-95CA-C5AB0DC85B11をconcatして、shaでdigestしたもののbase64エンコードした値です。えっ?何言ってんだって?コードだと

s = sec_websocket_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
digest = sha.sha(s).digest()
print base64.encodestring(digest).lower()

と言うことです。これでサーバからのレスポンスのSec-WebSocket-Acceptと、クライアントで計算した値が同じであればハンドシェークは成功です。まあ、厳密いえばUpgradeヘッダーとかその辺の値のバリデーションも必要なんですが・・・。

でも、大昔よりは幾分シンプルになりましたね。

次回は実際のデータ転送について。