今も昔も「入力によって挙動が大幅に変わるAPI」が世の中には多数存在していて、プログラマが本来意図した挙動と異なる動作を引き起こしている。
- ファイルを開こうとしたらコマンドを実行できてしまったり
- CSSセレクタを書いてるつもりがHTMLタグを生成してしまったり
- SELECT文を発行するつもりがDELETE文を発行できてしまったり
こういったときに
- 入力値検証をしないと危険になる
- 特定文字列のエスケープをしないと危険になる
と教えることは、時に害悪であると思う。なぜかというと、そういうことを知らないと安全にならない設計がそもそも危険だからだ。 あるいは、知っていたとしても「自分の仕事ではない」と思ってしまったり「ライブラリ側で対策されているはずだ」と思ってしまうことで、サボる。 入力値が別の箇所で検証されているはずだ、とか、ここには数値しか入らないはずだ、と思い込んでサボる。 あるいは全部自分の仕事だと思って、B'z って検索したら B\' って出力されるような面白アプリケーションが出来上がる。
SQLインジェクションは知っていても(NoSQLな何か)インジェクションは知らない、とか、文字コードが絡んだ複雑なケース、一見安全そうに見えるのに実は危険なコード。世の中には罠がたくさんある。 脆弱性を検査する立場にいるときに、マニアックな攻撃手法をたくさん「知っている」ことは強みになるけれど、全てのプログラマに同等の知識を期待すべきではない。(ただのバッドノウハウだ) 他人が知らないことを知っている、他人が気付かないことに気付くことが出来る、というのは強みになるし、バグを発見するということに関して、とてつもなく稀有な才能を持っている人もいる。 けれど、プログラマが気を使わなければいけないことは可能な限り減らした方がいい。
ライブラリ利用者側は、
- 何が起こるか予測不能になるAPIの利用を避ける(低レベルの、危険な動作を引き起こしうるAPIを直接使わない)
ライブラリ作成者側は、
- 何かを「忘れる」あるいは何かを「知らない」と危険になってしまうようなAPI設計を避ける
- 生Rawダイレクト高速低レベル危険な動作を引き起こしうるライブラリであるなら、その旨を明記する
ことが肝要であると思う。
多く新規のコードが書かれる(新規のバグが発生する)部分においては、入力値の検証やエスケープ処理を忘れても、 原理的に脆弱性が発生しないような、何が入力されても予想外のことが起こらないような、ラッパーを介して使うのが良い。 そうすることで自然と「安全かどうか検証しやすいコード」になる。
問題はというと、安全なラッパーだと思って使っていたライブラリが実は入力値検証やエスケープ処理が必要で「え、俺?それ俺の仕事だったの?」ってなることだ。 そして後方互換性のためと言って、危険なことが起こりうるAPIのまま、変更できなくなってしまうことだ。 紆余曲折を経て変更されたはずが何故かMigrate Pluginなどというもので復活してしまうことだ。jQueryやめろ。