第1章 セキュアWebプログラミング
[1-4.]
クエリストリングから情報が漏れる
クエリストリングはWebページ間で手軽にパラメタを受渡しできる方法であるが,ユーザの目に最も触れやすく改竄が容易である。また,ブラウザが生成するRefererヘッダにより他のWebサイトにも情報が漏れる。クエリストリングには決して重要な情報を含めてはならない。



PDF
● ● ●
クエリストリングは丸見えで改竄も容易
まずリスト1のURLを見ていただきたい。これは架空のWebメールサイトのURLの例である。ユーザがある受信メールを読むとき,ブラウザのアドレス欄に表示されるであろうURLである。このURLからユーザはどんなことを想像するであろうか。
リスト1 架空のWeb メールサイトのURL の例
http://www.victimail.jp/cgi-bin/showmail.cgi?user=97044710&pw=0409&mbox=1&mailid=385
注目するのはクエリストリング(URLの?以降の部分)であろう。"user=97044710"と"pw=0409"の部分は自分のユーザIDとパスワードであることが容易に理解できる。Webページ間でパラメタを受け渡すことにより,Webアプリケーションはユーザを特定し,認証を自動化している。また"mbox=1"はメールボックスの1番目ということで,現在表示中の受信トレイがメールボックスの1番目であろうと想像できる。"mailid=385"はメールボックス中の個々のメールにつけられたIDであるのだろうと想像できる。このようにクエリストリングに含まれた情報は丸見えで,Webアプリケーションの仕組みを想像することもできる。
 
ここまで想像を膨らませたユーザなら,きっと"mailid=386"とURLを変更し,リターンを押すだろう。その結果として実際に次のメールの本文が表示されることだろう。ブラウザのアドレス欄でタイプするだけなので非常に改竄も容易である。
 
もしユーザが悪意ある人物であれば,きっとこう考えるであろう。「user部分の数値を97044711に変えて,誕生日をパスワードにする人が多いからpw部分に"0101"〜"1231"までの366パターンを試すと,ユーザIDが97044711の人のメールを読めたりするかも!」こうして悪意あるユーザはクエリストリングの数値を変化させてアクセスする自動化ツールを作成し,横断的に他ユーザのパスワードを調べまくるかもしれない。
クエリストリングはいたるところに露出している
クエリストリングはURLの一部である。そのURLはユーザが知らないうちにさまざまな個所に記録されている。次のような個所に記録されていることが一般的に知られている。
  • Webサーバのアクセスログ
  • ファイアウォールログ
  • プロキシサーバのキャッシュやログ
  • ブラウザのキャッシュや履歴
Webサーバのアクセスログ,ファイアウォールログ,プロキシサーバのキャッシュやログに記録されたURLは,サーバ管理者なら簡単に参照することができる。また複数のユーザで共用するPCで個人がWebメールサイトへアクセスした場合など,ブラウザのキャッシュや履歴にURLが記録される。共用PCなので,他のユーザもそのキャッシュや履歴を参照できてしまう。
 
ユーザがWebページのリンクをクリックしたときなど,ブラウザはそれまで表示していたWebページのURLをリンク先のWebサーバへ知らせる。これはHTTPリクエストのRefererヘッダによるもので,Webサーバ管理者が自分のWebサイトにどこのWebページからリンクが張られているのかを知ることができる機能である。リスト2にHTTPリクエストのRefererヘッダにIPAのWebサイトのトップページのURLが含まれている例を示す。これは実際にIPAのトップページからリンクをクリックしたときのHTTPリクエストをキャプチャしたものである。
リスト2 HTTP リクエストに含まれるReferer ヘッダ
1 GET /ipa/biz/security/img/item.gif HTTP/1.1              ←リンク先
2 Accept: */*
3 Referer: http://www.ipa.go.jp/ipa/biz/security/main.html ←IPA トップページのURL
4 Accept-Language: ja
5 Accept-Encoding: gzip, deflate
6 If-Modified-Since: Mon, 03 Jul 2000 19:48:14 GMT; length=659
7 User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; windows NT 5.0)
8 Host: www.ipa.go.jp
9 Connection: Keep-Alive
このようにURLの一部であるクエリストリングはいたるところに露出している。悪意ある人物にWebメールなどのクエリストリングを見られてしまった場合,メールの内容を盗み読まれてしまうことだろう。
クエリストリングの用途
一般にクエリストリングは次のような用途に使用されている。
  • ユーザが入力したパラメタの送信
  • Webページ間のパラメタ受け渡し
  • Webアプリケーションへのパラメタ付きリンク
ユーザがWebページ上のフォーム項目で入力したパラメタはクエリストリングに乗せてWebアプリケーションへ送られる。ただしフォームの送信方法がGETの場合である。後述するがフォームの送信方法をPOSTとした場合にはパラメタの送信にクエリストリングは使用されない。
 
リスト1のURLで例に挙げたようなWebメールアプリケーションなどは,Webページ間でパラメタを受け渡すためにクエリストリングを使用する。後述するようにクエリストリングを使わない手法もあるが,クエリストリングにパラメタを埋め込む手法は手軽に実装できるため多用されている。
 
リスト3にWebアプリケーションへのパラメタ付きリンクの例を示す。架空の掲示板サイトにおける記事一覧ページのHTMLである。Aタグのhref属性のURLを見て欲しい。Webアプリケーションのbbs.cgiというサーバサイドスクリプトへ,表示させたい記事の記事番号をクエリストリング"article="で指定している。クエリストリング"?article="で指定する記事番号を変えただけのAタグを列挙するだけで,記事一覧のリンクページができあがる。クエリストリングはURLの一部であるため,WebアプリケーションへのURLにパラメタを同居させることができる。Webブラウザのブックマークに保存するとき,記事番号がクエリストリングとしてURLに含まれているので,記事へのリンクが損なわれることはない。
リスト3 Web アプリケーションへのパラメタ付きリンク
1 <A href="/cgi-bin/bbs.cgi?article=1">はじめまして</A><BR>
2 <A href="/cgi-bin/bbs.cgi?article=2">Re:はじめまして</A><BR>
3 <A href="/cgi-bin/bbs.cgi?article=3">PerlのNULL Poisoningって何ですか?</A><BR>
4 <A href="/cgi-bin/bbs.cgi?article=4">Re:PerlのNULL Poisoningって何ですか?</A><BR>
5 <A href="/cgi-bin/bbs.cgi?article=5">Re:Re:PerlのNULL Poisoningって何ですか?</A><BR>
このようにクエリストリングは手軽且つ便利な機能である。
扱う情報を分類しよう
前述のとおりURLに含まれたクエリストリングは多くの場所に露出し得る。したがって,漏洩しては困る重要な情報をクエリストリングに含めてはならない。しかしクエリストリングは便利でもある。扱う情報に合わせてクエリストリングを用いる場合と用いない場合の使い分けが必要である。
 
一般的に以下のような情報は露出すると困るであろう。
  • パスワード
  • Webメールのメール内容などの個人用データ
  • 名前,年齢,住所などの個人情報
  • Webアプリケーション内部のデータ構造
  • Webサーバ内部のフルパスなどの各種システム情報
露出して困る情報と露出しても困らない情報の分類はWebアプリケーションごとに異なるので,Webアプリケーション設計時に吟味すべきである。露出して困る情報を扱う場合は以下で説明するクエリストリングを使用しない手法で設計して欲しい。
ユーザ入力フォームの送信にはPOSTを使おう
ユーザが入力したパラメタをWebアプリケーションに送るとき,多くの場所に情報が露出されるのを避けるためには,クエリストリングではなくPOSTを使用しよう。フォームの送信方法(メソッド)にはGETとPOSTの2つがある。GETを使用した場合,ユーザが入力したパラメタはクエリストリングとしてWebアプリケーションへ送られる。サンプルのHTMLをリスト4に,そのスクリーンショットを画面1に,送信ボタンを押したときブラウザのアドレス欄に表示されるURLをリスト5に示す。驚いたことに画面1のパスワード入力欄ではパスワードが"*"文字で隠されているのにも関わらず,リスト5で示したURLのクエリストリングにはバッチリと"pw=0105"と表示されている。このように露出しては困る情報をGETを使って送信してはならない。
リスト4 フォームをGETで送るHTML
1  <FORM method="GET" action="login.cgi">	          ←GETである
2  ユーザ名<INPUT type="text" name="user"><BR>
3  パスワード<INPUT type="password" name="pw"><BR>	←パスワード
4  <INPUT type="submit">
画面1 フォームのスクリーンショット
 画面1 フォームのスクリーンショット
リスト5 GETの場合のURL
http://victimail/cgi-bin/login.cgi?user=mat&pw=0105 ←パスワード丸見え
POSTを使ったサンプルのHTMLをリスト6に示す。これはリスト4のHTMLの"GET"部分を"POST"に変えただけである。送信ボタンを押したとき,リスト7のようなURLがブラウザのアドレス欄に表示される。リスト7が示すとおり,POSTを使うとURLはクエリストリングを含まない形になる。ユーザが入力したパラメタが多くの場所に露出することを防ぐことができる。
リスト6 フォームをPOSTで送るHTML
1  <FORM method="POST" action="login.cgi">     ←POSTである
2  ユーザ名<INPUT type="text" name="user"><BR>
3  パスワード<INPUT type="password" name="pw"><BR>  ←パスワード
4  <INPUT type="submit">
リスト7 POSTの場合のURL
http://victimail/cgi-bin/login.cgi                  ←クエリストリングは付かない
ではユーザが入力したパラメタはどうやってWebアプリケーションへ送られるのだろうか。答えはリスト8に示したHTTPリクエストにある。このHTTPリクエストはブラウザがWebアプリケーションに送る実際のリクエストデータをキャプチャしたものである。1行目からPOSTリクエストであることが分かる。12行目が空行になっており,11行目までがリクエストヘッダ,13行目以降がリクエストボディであることを示している。13行目のリクエストボディ部にユーザが入力したパラメタがある。このようにPOSTを使用した場合,ユーザ入力パラメタはURLのクエリストリングではなく,リクエストボディに入れられてWebアプリケーションへ送信される。一般的にリクエストボディはログなどに記録されないため,GETよりPOSTの方が情報漏洩に対して安全である。
リスト8 POST の場合はパラメタはHTTP リクエストボディで送信
 1  POST /cgi-bin/login.cgi HTTP/1.1 ←POSTである
 2  Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/
     vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
 3  Referer: http://victimail/login.html
 4  Accept-Language: ja
 5  Content-Type: application/x-www-form-urlencoded
 6  Accept-Encoding: gzip, deflate
 7  User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)
 8  Host: victimail
 9  Content-Length: 16
10  Connection: Keep-Alive
11  Cache-Control: no-cache
12  
13  user=mat&pw=0105               ←ユーザ入力パラメタはHTTPリクエストボディで送られる
Webページ間のパラメタ受け渡しにはセッションを使おう
Webページ間で受け渡すパラメタにはWebサーバ内部の情報やユーザの個人情報が含まれることが多い。クエリストリングを使わずにWebページ間でこうしたパラメタを受け渡す手法として定番の手法がある。セッションメカニズムである。
 
セッションメカニズムは病院のカルテの仕組みと似ている。患者が初診で病院へ来た場合,病院は診察券とカルテを発行する。診察時に医者はカルテへその患者の病状や処置を記録する。その日の診察が終わると患者は診察券だけを受け取り帰宅する。カルテは病院で保管する。次回以降の診察では患者が診察券を病院側へ提示する。この診察券とペアのカルテを保管場所から取り出し,医者は同様に診察を行う。そして患者は診察券だけを受け取り帰宅し,病院はカルテを保管する。
 
セッションメカニズムでは,初めてユーザがWebアプリケーションへアクセスすると,WebアプリケーションはセッションIDとセッション変数を発行する。セッションIDはランダムでユニークな識別子で診察券に相当する。セッション変数はユーザ専用の記憶域でカルテに相当する。Webアプリケーションは次のWebページへ渡したいパラメタをセッション変数へ記録する。Webページの出力時にセッションIDをCookieに乗せてブラウザへ送り返す。以降ブラウザがアクセスしてくる時は,ブラウザはセッションIDをCookieに乗せてWebアプリケーションへ送ってくる。WebアプリケーションはそのセッションIDとペアのセッション変数をセッション管理テーブルから取り出し,前のWebページからのパラメタを受け取る。処理を行った後は,同様に次のWebページへ渡したいパラメタをセッション変数へ記録する。
 
セッションメカニズムでは重要な情報を一切ブラウザへ送信せず,セッションIDという情報へのラベルのみ送信する。重要な情報はWebサーバ内部に保管されるため,情報漏洩の危険性を抑えることができる。またセッションメカニズムは各種Webアプリケーション開発環境でライブラリやクラスとして提供されているので是非とも活用して欲しい。
その他の対策
上記に加えて次の対策を併用することで,更に情報漏洩の危険性を抑えることができる。Webアプリケーションの重要度に応じて検討してみて欲しい。
  • SSLによる暗号化通信
  • クロスサイトスクリプティング脆弱性対策
  • セッションハイジャック対策
SSLによる暗号化通信により,更なる情報露出の危険性を抑えることができる。クロスサイトスクリプティング脆弱性対策については『1‐2.クロスサイトスクリプティング』を参照して欲しい。
 
セッションハイジャックとはユーザのセッションIDを奪取しそのユーザになりすます行為である。セッションハイジャック対策には大きく分けて次の2種類がある。
  • セッションIDを漏洩しない対策
  • セッションIDが漏洩したときの対策
前者にはSSLによる通信路暗号化対策や,クロスサイトスクリプティングなどのクッキー漏洩対策などがある。後者にはセッションIDの有効期間を設定する対策や,クライアントIPアドレスをチェックする対策などがある。セッションIDの有効期間を設定する対策については,『5‐3.セッションタイムアウト』を参照して欲しい。
まとめ
クエリストリングはとても便利な機能で手軽に利用できる。しかし多くの場所に露出し得るため情報漏洩の危険性も併せ持つ。またクエリストリングを使って受け渡される情報は,容易に改竄され得る。したがって,重要な情報を扱う場合はクエリストリングを使ってはならない。POSTによるフォーム送信を利用すれば重要な情報が露出することを防げる。セッションメカニズムを利用すれば重要な情報が改竄されることを防げる。扱う情報の用途や重要度に応じて,クエリストリングやPOST送信,セッションメカニズム等を使い分けるべきである。
参考文献
『セキュアWeb プログラミング』,佐名木智貴
『特集 狙われるWeb アプリケーション』,高橋 信頼,「日経オープンシステム」2000 年12 月号
『セキュアWeb プログラミング』,佐名木智貴,「World PC Expo 2001 セキュリティスタジアム2001 」
『ASP とWeb セッション管理』,Michael P.Levy ,Senior Consultant ,Microsoft Consulting Services
『LXXIX セッション処理関数』,the PHP Documentation Group