問題はエンコーディングではないのだ。

http://itpro.nikkeibp.co.jp/article/COLUMN/20090208/324377/?ST=security&P=1からhttp://d.hatena.ne.jp/tohokuaiki/20090910/encodingの話。

ベースライン。

Webアプリケーション、ここでは一般的な用法として次の条件を満たすもの、の話に限定して進めよう。

  • サーバ・クライアント型のアプリケーションである。
  • http経由で通信する。

サーバ・クライアント型。

間に通信層が挟まっている以上、通信層の信頼性を考慮しなくてはならない。
限定少数の利用者しかいない有線LANならば、パケット化けは起こるとしても、意図的な攻撃を想定する必要はないかもしれない。利用者が増えるにしたがってワームに感染したPCが混じっている可能性も高まるだろう。無線LANならば管理者の気付かぬうちに利用端末が増えている可能性も考慮した方が良いだろう。この辺りの管理は悩みどころだ。
翻ってインターネットを経由する場合は悩むまでもない。潜在的な攻撃者がいることが前提であり、攻撃に晒されることを想定して開発する、という以外の選択肢はそもそもあり得ない。

http経由。

httpのGETやPOSTメソッドを用いた通信が主流だ。さて、GETやPOSTによって送られるパラメータは何者だろうか?
パラメータは決して文字列ではない。それどころかバイト列ですらない。答えはオクテット列だ。

メッセージ {message}
section 4 にて定義される構文を持ち構造化されたオクテットシーケンスから成り、接続を介して転送される、HTTP 通信での基本単位。
http://www.studyinghttp.net/rfc_ja/rfc2616より引用。

つまり。

ただのオクテット列をそのまま文字列として扱えば不都合が出るのは当然だろう。ここでしている操作はC++で言えばreinterpret_castなのだから。もしオクテット列が想定している文字エンコードに合致していたとすれば、それは単に幸運だったのだと思うくらいでちょうど良い。

len = fread(buff, sizeof(buff[0]), buff, fp);
str = reinterpret_cast<LPTSTR>(buff);

〆。

で、対策は次の通り。要するに「自分が欲しいもの=文字列」と「実際に受け取るもの=オクテット列」を区別すれば良い。

  1. 文字列を期待しているパラメータは、最初にオクテット列から文字列への変換を行う。
  2. 文字列の処理はそのエンコーディングに対応した文字列処理関数だけを使う。