第4回 隠したよ 隠れてるわけじゃ ないけれど - セキュリティ講座

PHP 中級 講座

がる先生のセキュリティ講座

Lecutures on PHP

第4回 隠したよ 隠れてるわけじゃ ないけれど (その1)

 このエントリーをはてなブックマークに追加

秘密にしてあるから大丈夫?

ある画面から次の画面に情報を渡すときに。多分、多くの人が、場合によっては半無意識的に使っているINPUTエレメントのtypeアトリビュート値hiddenな項目。
hiddenの名のとおり「HTMLの表示項目としては見ることの出来ない」隠された項目である…ことに間違いはないのですが。 このhidden。使い方をちょっと工夫するととても便利なものなのです………クラッカーたちにとって。

よくある…危険性

がる先生もしかすると「一番なじみがある」といってもいいかもしれない使い方と、その危険性について言及してみましょう。
あるWebの一連の画面があります。それは「入力画面(入力.php)確認画面(確認.php)完了画面」という3画面構成です。画面と画面の間にある*.phpが、phpプログラムになります。

一番初めに大抵の人が悩むのが「確認画面から完了画面に遷移するときの"確認.php"で、入力画面からの情報が受け取れない」部分です。 多くの書籍、Webでは、ここで「hiddenを使って確認画面に情報を埋め込むこと」を推奨しています。

これが「個人や身内で使うもの」であればよいのですが、セキュリティを基準に考えた場合少々面倒が起き易いのもまた事実です。 ではその「面倒」な状況を、実際に流れに沿って追いかけてみましょう。

入力.phpでは、大抵の場合「入力チェック」を行い、データ的にNGだったりしたものについてはダメ出しをします(ここでエラー画面を表示するか入力画面に戻してエラー表示するかはお好みです)。 そうして、確認.phpでは、すでに入力チェックが終わった情報を受け取るので、必要な情報をファイルやDBに格納する処理を記述します。

………という記述に対して疑いなくうなずいた人は、気をつけましょう。クラックの被害にあう可能性があります。
確認画面の中のhiddenは、ほんのわずかにHTMLの知識がある程度で、十分に書き換えることが出来ます。つまり、上述の流れを踏襲すると「確認画面をこそこそっと書き換えて」動かし直すことで、事実上「ノーチェックのデータが」格納されてしまいます。

つまり、最低限

  • 入力.phpとまったく同一のデータチェックを確認.phpでも行う

必要がある事がわかります。がる先生

(なおここで稀に「REFERERを見て…」という処理を拝見しますが、REFERERは別のセキュリティ上などの理由で「送出しないように設定しているユーザ」や「REFERERヘッダを削ってくれるパーソナルファイアウォール」などもあるので、あまり前向きな発想ではありません。REFERERヘッダの偽装も容易ですし) ただ、チェックをしてなお「hiddenに書かれたくない情報」というのは存在します。

筆者が個人的に「これがhiddenに書かれているとウンザリする」内容としては

  • パスワード
  • クレジットカード情報

があります。

個人情報がキャッシュファイルとして残る可能性、パケットという状態で何度もネットワーク上を往復する可能性を考えると、たとえ氏名ですら「嫌だ」と感じる人も少なからずいることでしょう(このあたりは、httpからhttpsにすることである程度緩和します)。 このあたりは判断が難しいところではあるのですが、意識しておいて損はないところです。

また、hiddenを用いた別のパターンで「情報が入っているクラスインスタンスをシリアライズして、そのシリアライズされた文字列をhiddenに格納する」という事例があります(Javaで比較的多く散見されるのですが、PHPでもありました)。
もしこの「シリアライズされた文字列を適切に解析してクラックできる文字列に入れ替えて戻したら」どうなるのでしょうか? ましてやそれがもしプログラム側で「hiddenで受け取った文字列をチェックもせずにアンシリアライズしてインスタンス化してしまった」としたら? 何が起きるか、何が出来るかについては、あえて言及いたしません。…あまりにもいろいろとひどいことができてしまいますので。…映画や漫画の残酷描写を省略するようなニュアンスを感じ取ってください。がる先生

hiddenという言葉に誤魔化されがちですが、hiddenは「見えないようにしている(隠れている)」だけであって、間違っても「見れないようにしている(隠している)」わけではないのです。
しかしつい多くの人はhiddenを「隠しておける場所である」と考えてしまい、つまりそれは「隠された、触れることのできない領域である」と錯覚し、その情報が入ってくるときに「チェックする」ことを忘れてしまうのです。その値が汚染されている可能性があるにもかかわらず。

ゆえに私は、よほど何か特殊な理由があってやむを得ずであり一時的にユーザにも許可を取った上でなお、hiddenに入力情報(もしくはそれに類するもの)を埋め込むことはまったくお勧めしません。
hiddenを万策尽きてやむを得ず使うのであれば、情報が毎回パケットとして垂れ流されていることを、キャッシュファイル内に書かれていることを加味した上で「必ず毎回」「同一の」チェックロジックによってすべての値を精査してください。

たまに見逃す人がいますが、SELECTエレメントの要素内のoptionだったりINPUTエレメントのtypeアトリビュート値がchecboxやradioだったりしても、必ずチェックしてください。
時々「textは書き換えられるけど、SELECT内のoptionとかINPUTのcheckbox、radioなどは固定値だから書き換えられない」と勘違いをしてしまう人がいるのですが、全部hiddenで置き換えることができる、つまりはいくらでも詐称できるのですから。
そうして、もし「常に毎回全部」チェックを「面倒だ」と思うなら、素直に「セッション変数」を用いてください。幸い、PHPにはセッション関数群があり、セッション変数という便利なものが用意されているのですから。

  • 1
  • 2

  



Pick Up Q&A

Q
負荷時のmysql_connect()エラー
 このエントリーをはてなブックマークに追加 
A
これはPHPというよりOSまたはMySQLのコミュニティで質問されたほうがいいと思います。 ぱっと思いついた範囲で記すと MySQL等のDBに「ある時点において同時に接続可能なクライアントの最大数」に制限があるよう...

>>続きを読む

今回のような実践的な経験がエンジニアのキャリアに繋がると思います。是非サービスを成功させて下さい!

▲解説者:岡本(アシアル株式会社 教育コーディネーター兼 システムエンジニア)