(注:記事は執筆時の情報に基づいており,現在では異なる場合があります)

インターネット上でWebアプリケーションを運用する場合,注意しなければならないのがセキュリティ対策です。ステップ7では,セキュアな(安全な)Webアプリケーションを開発するために,ぜひ知っておきたいポイントを紹介しましょう。

図1●購入金額を計算するWebアプリケーション
図2●改ざんされた計算結果。99%の割引率で10円になってしまった
図3●複数の画面にまたがって情報を渡すWebアプリケーション
リスト1
リスト2
リスト3
リスト4
リスト5

ポイント1
サーバーで入力値をチェックしHTMLフォームの改ざんを防ぐ

 図1[拡大表示]は割引コースを選択して定価を入力すると,購入代金を表示するWebアプリケーションです。HTMLフォームのコードはリスト1[拡大表示],サーバー側で購入代金を計算するPHPスクリプトはリスト2[拡大表示]です。リスト1で<select>~<option>タグに,10%,25%,35%の三つの割引率が設定され,リスト2では,その値が$_POST['rate']によって呼び出されていることがわかると思います。

 しかし,このアプリケーションには問題があります。それは「HTMLフォーム改ざんの危険性」です。

 ここに,悪意のあるユーザーがいたとしましょう。彼はこのアプリケーションを見て,割引率を勝手に変更し,不正な購入代金を請求しようと思いました。彼はまず図1のHTMLフォームをブラウザに表示すると,そのソースをチェックします。中身はリスト1のようになっているはずです。そこで彼はこのソースコードの内容をそっくりコピーし,自分のパソコンに同じ内容のHTMLファイル(例えばC:\sec0henko.html)を作成します。そして,<form>タグのaction属性部分をhttp://127.0.0.1/sample/keisan.phpという絶対指定に,<select>タグの割引率をすべて99%に書き換えます(リスト3[拡大表示])。

 「改ざんしたと言ってもただのHTMLファイル。拡張子が .phpになっていないし,そもそもローカルのパソコンにあるHTMLならサーバーサイドで処理されない」と思っていませんか? では実際に,改ざんしたC:\sec0henko.htmlをブラウザで開いてみましょう。URLはhttp://~ではなく,C:\sec0henko.htmlとなっているはずです。ところが,計算ボタンをクリックすると,なんと改ざんされた割引率で計算されてしまうのです!(図2[拡大表示])。

 確かにリスト3はHTMLファイルですからPHP処理とは無関係です。しかしリスト3のように,URLでサーバー上にあるPHPスクリプトをダイレクトに指定されてしまうと,HTMLファイルからPHPスクリプトを実行できてしまうわけです。

 では,このようなHTMLフォームの改ざんを防止するにはどうしたらいいでしょう。真っ先に思いつくのは,ステップ3で紹介したJavaScriptのスクリプトを埋め込む方法でしょう。しかし,JavaScriptのコードはブラウザで見ることができます。たとえJavaScriptのスクリプト部分を外部ファイルにしたとしても,ブラウザのアドレス欄に外部ファイル名を指定されたら,簡単にスクリプトの内容がのぞかれてしまいます。

 より有効な対策は,サーバー側のプログラム(ここではリスト2のkeisan.php)で,ユーザーが入力した値をチェックすることです。割引率が10%,25%,35%しかないなら,購入代金計算の前に,その値をチェックするのです。例えば,リスト2をリスト4[拡大表示]のように書き直してみてください。if文で値をチェックするようにしました。今度は,改ざんされたHTMLフォームを実行しても「その割引率は設定されていません」と表示されるはずです。

 HTMLフォームを作る場合は,必ずサーバー側で入力値をチェックするようにしてください。

ポイント2
とっても危険なhidden

 Webアプリケーションを作るとき,最も迷いやすいのが複数の画面にわたって,変数の値を使いまわす処理の記述です。

 例えば図3[拡大表示]は,(a)のHTMLフォームで名前とパスワードを入力してinputボタンを押すと(b)のHTMLフォームを表示し,(b)で性別と住所を入力してinputボタンを押すと,(a)と(b)で入力した値を(c)の画面で表示するWebアプリケーションです。ログイン情報を設定する場合など,インターネット上でも似たような処理をよく見かけますよね。一見,なんでもないことのようですが,実際にこの処理をPHPスクリプトでコーディングする場合,どうすればいいかわかりますか?

 Webアプリケーションは,ブラウザがサーバーにリクエストを発行し(ブラウザでアクセスし),サーバーがその結果を返す(ブラウザに表示する)という簡単なやりとりで成り立っています。ところがサーバーはたとえて言うなら“忘れっぽく”,このやりとりを1回限りしか覚えておけません。同じブラウザが再びサーバーにリクエストを発行しても,サーバーからすると,まったく別のリクエストとして認識します。つまり,(a)の画面から(b)の画面に移ったブラウザと,(b)の画面から(c)の画面に移ったブラウザは別のものと考えます。では,(b)から(c)の画面に移るとき,(a)で入力した値はどうやって覚えておけばいいのでしょう?

 そこでよく用いられるのが,HTMLの<input>タグにあるtype属性でhiddenを使う方法です。type属性をhiddenにするとブラウザには表示されなくなることを利用します。サーバーが忘れてしまっても,ブラウザで覚えておこうというわけです。この例なら,(a)の画面(リスト5[拡大表示])で入力された名前とパスワードは,それぞれ$_POST['username'],$_POST['passwd']として取得できるので,(b)のHTMLフォームを表示するときに,

<input type="hidden"
name="username"
value="<?=
$_POST['username'] ?>">
<input type="hidden"
name="passwd"
value="<?=
$_POST['passwd'] ?>">

などとして,値を(c)の画面に引き渡すのです。これなら(c)のスクリプトでも,$_POST['username']とすれば(a)で設定した値を取り出せます。

 しかし,hiddenを使う方法は危険です。ブラウザに表示されないと言っても,HTMLデータはブラウザに送信されているからです。ブラウザで(b)の画面のソースを見たら,たちまち上記のコードが表示されて,(a)の画面で入力した値がわかってしまうでしょう。

(真島 馨=日経ソフトウエア)

(次回に続く)