アプリケーションプロトコル設計のベストプラクティス (over TCP)
みたいなものを誰かまとめてないのかな、と思ってる。ないのかな。とりあえず自分用メモ。
概要
デリミタ方式
テキストプロトコル系で一般的。ペイロード内にデリミタが出現する場合はエスケープ。
- 問題は遅いこと
- メタ情報のみデリミタでコンテンツは length というモデルも (HTTP)
- デリミタの定義をはっきりさせること
- 例: HTTP の "Content-Length :" セキュリティホール
その他バイナリ系
Type 等のコンテクストによって Value のパーサが決まるので length が不要だったりして (あまり) 冗長じゃないプロトコル。ASN.1 PER 系や DNS 等。
- いろいろ支援機構がないと辛い
- 解析が、とても面倒
- 全体を理解するパーサを作らないと、部分的な解析すらできない
- 解析が、とても面倒
- UDP 1パケットに収めたいといった場合に便利
構造化の留意点
- レイヤをきちんと分けること
- 上位レイヤ (例: コマンド名) によって、下位レイヤの処理を変えるのはダメ
- 反例: STOMP の ERROR メッセージ
- 上位レイヤ (例: コマンド名) によって、下位レイヤの処理を変えるのはダメ
- required と optional をはっきりさせること
- 電文内のフラグで表現可能にする場合は、「未知のフィールドがrequiredだったらfatal」に限定すべき
- otherwise security problems arise
- 電文内のフラグで表現可能にする場合は、「未知のフィールドがrequiredだったらfatal」に限定すべき
- PER のような方式でない限り、値が複数回指定できる構造化方式にならざるを得ない点に留意
- 1回しか指定されるべきでない値が複数回指定された場合、最初のものを優先するのか最後のものを使用するのか明確にすべき
- 参考: メモ - 葉っぱ日記
- 1回しか指定されるべきでない値が複数回指定された場合、最初のものを優先するのか最後のものを使用するのか明確にすべき
- 複数の構造化方法の混在は危険
- 反例: HTTP splitting attack using content-length and content-encoding
最適化
- TLVにせよデリミタにせよ、バッファリングが必要
- パイプライン化を仕様で禁止するなら、なくてもなんとかなるけどさ
- バイナリプロトコルなら、1バイトの電文を駆使するという技も
- ACK,NCK 等で有効
パイプライン処理
- パイプライン処理を認める場合、close(2) は禁止
- タイミングによって RST が発生し、その結果、電文が欠落するため
- 参考: Connections in FIN_WAIT_2 and Apache
- パイプラインをやるなら、必ず shutdown(WR) して相手が close するのを待つこと
- latency がそれほど問題にならないイントラネットのプロトコルでは、パイプラインを禁止するのも手
以下続く、かもしれない。