「やるべきことをやろうよ」で、問題を提起したので、対策を考えるエントリ。
このエントリの「コメント」に対するルール:
「コメント」は、1行目に「コメント」と書く。
「対策」の場合は、1行目に「傾向と対策」と書き、どういう攻撃パターンに対してどの様な対策が有効かを書いてください。この場合、本文に取り上げさせて頂きます。
インジェクション(挿入)系の攻撃
データベースに対するSQL インジェクションが有名だが、OS コマンド、アプリケーションのマクロを挿入したり、あるいはパラメータを改竄するなど、様々に派生する。クロスサイトスクリプティングも、スクリプトを挿入するという意味でここに含む。
対策としては、基本的に、「やるべきことをやる」。
そこに入力されるものの性質を考え、まずは必要なものだけを入力させる(入力を許可する)。入力されたものが何に使われるかを考え、使われるところで特殊な文字はないか、調査する。例えば、HTML 出力するなら "<" と、それに続くアルファベットなど。データベース系なら引用符など。そういった特殊文字を含む場合は、特殊機能を回避する方法を調べて、文字列の置換を行う。
入力されるべき文字列は、ほとんどの場合、処理系に対して特殊な動作を要請するものではなく、「人間の目に見えるように表示されるもの」であるはず。人間の目に見えるように表示して初めて、「やるべきことをやった」と言えないか。
挿入するのではなく、書き換える場合もある。HTML における input 要素の type 属性を hidden に設定すると、ブラウザはこれを表示しない。これは、ブラウザが表示をしないだけで、送信しないわけではない。「hidden は見えないから」と、ここに重要な情報を書いている場合がある。これは、簡単に読まれたり、書き換えられたりする。「表示されていない」ことを過信してはいけない。ASP.NET においては、ViewState が hidden 属性の input 要素に書き込まれる。これは、一見暗号化されているように見える。しかし、デフォルトではバイナリシリアル化したものを Base64 エンコードしているだけで、簡単に元の値を取り出せる。
HTML のソースを見ることに対する対策として、 JavaScript でマウスの右クリックを Off にし、ソースの表示を禁止することがある。この場合、JavaScript を Off にされれば無効だし、Opera など、JavaScript を On のまま、右クリックを禁止するスクリプトだけを Off にすることが出来るものもある。第一、攻撃者が自作したエージェントを使われれば、全く無駄である。RSS リーダーやオークション自動化ツールなど、そういったものは(ある人には)簡単に作れることを憶えておくと良いだろう。
足跡をたどったり、証拠を残すために、リファラーやエージェントタイプなど、一般ユーザが手を加えない文字列を取り込むことがある。このときも、「ブラウザが設定するものだから」と、これらの値を無チェックで使用してはいけない。これらの文字列も、書き換え可能である。ここに XSS のための文字列を仕込まれるかもしれない。
パス(ディレクトリ)トラバーサルなどに対しては、安易に「../」などだけを検証するのではなく、絶対パスに変換するなどして、アプリケーションがアクセスしてもよいディレクトリ以下にあるかどうかを検証する。
強制ブラウジングはブルートフォース系の攻撃であるが、対策はインジェクション系の攻撃と同じく、正当性の検査を行う。
アプリケーションは、自身に与えられた範囲で動作を行うことを求められている。ここでやるべきことは、「与えられた範囲内で動作する」ことである。
このとき、「禁止リスト」ではなく、「許可リスト」を作る。禁止リストから漏れることは多いが、許可できていたものが攻撃につながることは、比較的少ない。
「全くない」とは言っていないことに注意。例えば、HTML の img 要素はどこかにある画像を表示する。この動作自体は無害なので、許可リストに加えても良い。しかし、特定のサーバにある画像へのリンクを大量に含むページを表示させようとするとどうなるか。サーバに対する DoS 攻撃につながる。そのページを表示するのが1人だけなら、そう問題ではない。しかし、同時に何百人もアクセスしてきたら、どうなるだろうか。また、JPEG ファイルなどでバッファオーバーランを引き起こしたり、画像ファイルを装った実行ファイルをダウンロード、実行させることにつながる恐れもある。
使用時に、使用先で無害な文字列になるように加工をすることを、「サニタイズ(サニタイジング・無害化)」と呼ぶことがある。しかし、設計時に使われるところで特殊文字と判断されるものを調査し、実装時に適切に変換する処理を組み込み、テストで確認していれば、取り立てて「サニタイズ」と叫ぶ必要はない。しかし、設計・実装・テストで万全を期し、さらに保険として Web アプリケーションファイアーウォールなどでサニタイズすることは有用である。
正しい入力を得るために、様々な入力を試みる。入力するものを辞書登録されている単語に絞ってヒット率を高める「辞書攻撃」も含む。
対策としては、基本的に、「情報を与えない」。
特に、システムが出す素のエラーメッセージを表示してはいけない。デバッグ中は便利だが、最終テストでは、それらが隠されていることを確認する。攻撃者はエラーメッセージから使用されている技術を推測し、その技術の公開されている脆弱性を使って攻撃してくるだろう。また、Blind SQL Injection という、エラーメッセージがなくても SQL Injection の脆弱性があることを予想した攻撃もあり得る。
「ログイン画面」においては、「ログイン名」の表示に「メールアドレス」など、他に意味を持った言葉を書かない。これにより、そこに何が入るか推測することを容易にするため。不定長の2つの文字列を推測するのは困難だが、メールアドレスなど公開されている文字列であることを明かすと、推測するのは1つで良くなる。さらに、その人の近辺から、パスワードとして使われている文字列を推測することも可能となる(例:キャッシュカードの暗証番号に、電話番号や誕生日を用いるなど)。
ログイン名とパスワードのチェックで、ログイン名だけが間違っている、またはパスワードだけが間違っていることを知らせない。どちらも間違っていると、表示する。または、どんな場合でも、あるいはランダムに「パスワードが間違っています」「登録されていません」と表示するのも良い。これにより、ログイン名とパスワードの正しい組み合わせを推測困難にする。
特に、ログイン名に「メールアドレス」と表示し(「ログイン名(メールアドレス)」など)、「ログイン名が違っています」というメッセージを表示するシステムでは、ログイン名だけを変えて何度もリクエストを送り、登録されたメールアドレスの一覧を取得することが可能になる。
ログイン画面だけでなく、パスワードリマインダでも同じことに注意する。
正しいログイン名と、間違ったパスワードの入力が数回続いた場合、該当するユーザをロックするシステムは多い。しかし、間違ったログイン名の入力が続いた場合、操作者を閉め出すシステムは少ない。これらの場合でも、「ロックされた」「閉め出した」という情報を、直接に与えない。
このように、情報を与えないと、攻撃に対しては強くなるが、使い勝手は悪くなる。適切なところで折り合いを付ける必要がある。
ただし、ユーザの情報を入力してもらうときは、どこが間違っている(と思われる)のか、明示する。ユーザエントリを作る時に「入力された情報に誤りがあります」だけだと、何を直さなければならないのか、わからない。また、ID(メールアドレスやログイン ID)をユーザに決めさせるときに、重複しているなど、情報を示さなければならないときもある。
パソコン通信時代、ユーザ ID は連番だった。このことから、「存在するユーザ ID」、ひいては「メールアドレス」を推測することが容易であり、これを利用した大量の広告メール送信が行われた。また、メーラーデーモンはたいていの場合、存在しないアドレスに対してメールが送られると、そのことを返信として通知する。これにより、「存在しないメールアドレス」が明らかになり、「送付したメールアドレス」から差し引くことで、「存在するメールアドレス」が明らかになる。過去のこのような事例から、「ID は連番にしない」「Not Send メールを送らない」ことが常識化しだしている。ただし、これにも「利便性とのトレードオフ」が存在する。
用意されている入力バッファを超える入力を送りつけ、他の変数や、時にはプログラムそのものを書き換えることで、システムに異常な動作を行わせたり、動作を停止させる。
対策としては、基本的に、「やるべきことをやる」。
入れ物の大きさを常に念頭に置き、取り込む長さを制限する。特に、「仕様でこの長さに決まっているから」というのは厳禁。その仕様を守らないツールを作られたり、後に仕様が変更になった場合のことも考えておく。
特に Web アプリケーションにおいては、「maxlength 属性で制限しているから」「スクリプトでチェックしてから送信しているから」と安心するのは厳禁。そのページをローカルに保存し、HTML を書き換えた後、再表示して maxlength を超える入力を送りつけることが可能。もちろん、HTML を動的に解析するプログラムを作れば、select 要素で選択できない値を送りつけることも可能。いったんユーザに渡る、入力値制御を信用してはいけない。
一般にこの手の攻撃に対しては、ユーザの入力を信じてはいけない。あるいは、悪意を持っていなくても、例えば「キーボードの上に本を置いた」などのうっかりミスはあり得る。本来入力されるもの以外の入力をされたときにも、システムが動作を継続出来るようにする。
投稿日時 : 2006年1月12日 19:59