- 2008/12/3 水曜日 5:44:14
- php
PHPで開発をすることが多くなりPerlの良さを再確認している今日この頃ですが皆さんいかがお過ごしでしょうか。
さて、今日は今もっともナウいPHPのWebアプリケーションフレームワークであるCakePHPのお話を一つ。
CakePHPには組み込みコンポーネントとしてリクエストハンドラ(RequestHandler)が備わっています。
リクエストハンドリング :: 組み込みのコンポーネント :: マニュアル :: 1.2 Collection :: The Cookbook:
このRequestHandlerのメソッドであるgetClientIPが小学生には危険そうだというお話。(あ、このエントリのタイトル逆w)
まずはgetClientIPの実装コードを。(1.2を例にとっているが1.1もほぼ一緒である)
https://trac.cakephp.org/browser/trunk/cake/1.2.x.x/cake/libs/controller/components/request_handler.php
function getClientIP() { if (env('HTTP_X_FORWARDED_FOR') != null) { $ipaddr = preg_replace('/(?:,.*)/', '', env('HTTP_X_FORWARDED_FOR')); } else { if (env('HTTP_CLIENT_IP') != null) { $ipaddr = env('HTTP_CLIENT_IP'); } else { $ipaddr = env('REMOTE_ADDR'); } } if (env('HTTP_CLIENTADDRESS') != null) { $tmpipaddr = env('HTTP_CLIENTADDRESS'); if (!empty($tmpipaddr)) { $ipaddr = preg_replace('/(?:,.*)/', '', $tmpipaddr); } } return trim($ipaddr); }
(envの実装はbasics.php。簡単にいってしまえば$_SERVERか$_ENVから指定されたkeyの値をとってくるというところ。)
ひええ。怖いですね。小学生には使いこなすのは厳しそうですね。それではみなさんご機嫌よう。
といって終わるのも不親切なので何がどう危険なのかを少し解説。
HTTP_X_FORWARDED_FORというのはhttpヘッダのFORWARDED_FORX-FORWARDED-FORのことで、これは一般的には、匿名ではないプロキシに接続している際にプロキシサーバがアクセス先のサーバにhttpリクエストのヘッダに勝手に送信元のIPアドレスを付与しちゃうものだ。
で、このコードではそのヘッダに何か値があればそれを送信元IPアドレスとして返してしまう。
ちなみにリバースプロキシを使っている時はmod_rpafやmod_extract_forwardedを使ってこのコードと同様のことをapacheレベルでやったりはする(mod_rpafとmod_extract_forwardedは置き換えのフックのタイミングが違ってたりする)。しかし決定的に違うのは、mod_rpafにしろmod_extract_forwardedにしろ、置き換えを許す送信元のプロキシのアドレスを限定する設定があるのだ。mod_rpafではRPAFproxy_ips、mod_extract_forwardedではMEFacceptがそれにあたる。ところがこのgetClientIPにはそういったコードは見当たらない。
ここで一度整理しておきたいが、phpで取得できる$_SERVER[‘REMOTE_ADDR’]はwebサーバに実際に接続してきたtcp/ipにおける送信元アドレスであり、3ウェイ・ハンドシェイクにより検証されている信頼性の高い送信元IPアドレスといえる(もちろんシーケンス番号の問題とかもあるが)。それに比べhttpリクエストヘッダに記述されるFORWARDED_FORX-FORWARDED-FORの値は、webサーバにとってはまったく検証を経ていない信頼性の低いアドレスなのである。
上記のことからわかるのはgetClientIPには任意のIPアドレスを注入できるということだ。要するにIP偽装(IP Spoofing)である。
ちなみにfirefoxであればアドオンのModify Headersなんかを使えば簡単にhttpヘッダは任意のものが作成できる。
ところで、WebアプリケーションにおいてIP偽装が問題になるのはどういう場面であろうか。それは認証に利用している場合であろう。日本に住んでいるwebエンジニアが真っ先に思いつくのは携帯の個体識別番号認証でのIPアドレスチェックではないだろうか。先日高木浩光氏に退化してゆく日本のWeb開発者と揶揄されていたが、個体識別番号認証自体を完全否定することは私にはできないが、少なくともCakePHPでモバイルサイトを構築されている方はこの件を確認していただくのがよいかとおもわれる。しかしたとえば携帯とPCでデザインを変えているだけなんて場合には影響は皆無であろう。
ちなみにこの件はCakePHP開発側に伝えるべきなのだろうか。しかしこれだけ確信的にコードに書かれていると「仕様です」という感じがしないでもない。
しかし、小学生が使うことも考慮して以下のマニュアル等には「よいこのみなさん、ここでえることのできるIPアドレスはほんとうのクライアントのIPアドレスとはちがうばあいがあるよ」ぐらいは書いておいてほしいものだ。
クライアントについての追加情報を取得する :: リクエストハンドリング :: 組み込みのコンポーネント :: マニュアル :
まぁとりあえず小学生は$_SERVER[‘REMOTE_ADDR’]を普通に使っておくとよいとおもわれる。
追記1: $_SERVER[‘HTTP_X_FORWARDE_FOR’]のhttpヘッダでのキーは”X-FORWARDED-FOR”ですた
- 新しい: そろそろCakePHPについて一言言っておくか
- 古い: 情けは人のためならず
コメント:0
- shun 2008/12/4 木曜日
Ticket出しておきました。
https://trac.cakephp.org/ticket/5842- 千葉征弘 2008/12/4 木曜日
あ、すみません。
わざわざありがとうございます。- 千葉征弘 2008/12/8 月曜日
んが。。。
いろいろいじってたら間違ってコメント消しちゃいました。
すみませんです・・・。>shunさん- Chiba Masahiro 2009/1/3 土曜日
なんかもどせたので戻しました
トラックバック:1
- この記事のトラックバック URL
- https://blog.everqueue.com/chiba/2008/12/03/31/trackback/
- トラックバックの送信元リスト
- CakePHPのgetClientIPを使っていいのは小学生までだよねー - へぼい日記 より
- pingback - 今日のピックアップ(2008/12/03) - sj6works より 2008/12/3 水曜日
[…] CakePHPのgetClientIPを使っていいのは小学生までだよねー そうだったのか・・・完全に小学生でした。 […]