Truncation脆弱性の話題になりました。Truncationは、2008年にWordPressの脆弱性として報告されたことがあります(参照、参照)。Truncationを説明したいと思います。認証に用いる会員テーブルを下記とします。一意制約がありません。(追記)一意制約はふつうあるだろと思われるでしょうが、CMS四天王の中で一意制約がついているのはDrupalのみで、WordPress、Joomla、MovableTypeには一意制約がついていません。sec)これで準備が出来ましたので、以下攻撃者の視点で攻撃に用いるSQLの呼び出しを見ていきましょう。(空白は3個)というログイン名を登録します。以下に示すのはmysqlコマンドにより、アプリケーション内部のSQL呼び出しを再現するものです(攻撃者が操作するのはあくまでWebアプリケーションです)。(adminの後に空白3個)が会員として登録されます。sec)なんと、ログインできてしまいます。これができる理由は、MySQLは基本的に文字列末尾のスペースを比較時に無視するからです。値が、末尾のスペースに関係なく比較されることを意味します。(false)になっています。adminでログインした状態で権限を確認するログインした後は通常ログイン済みのログイン名をセッション変数に記憶しておく形でログイン状態を保持します。権限が必要になる都度データベースに問い合わせると想定します。以下のSQL文を用います。sec)idとusernameは処理の上では必要ありませんが、説明のために追加しています。攻撃者は管理者の権限を得ることに成功しました。脆弱性の原因は、元々ユニークであることを想定していたusername列に、同一とみなされる名前が登録されることにあります。その原因は、列の最大長を超える文字列をINSERTする際に、文字列が切り詰められ、インサート後の文字列がチェックの時とは別の文字列に変わることにあります。Truncationの対策は、文字列の切り詰めが発生しないようにするか、文字列の切り詰めが発生しても列のユニーク性が保証される方法をとることで、具体的には以下の方法があります。Server等を使用するMySQLのsql_modeをstrictモードにする(追記)username列に一意制約を指定するいずれか一つの方法で対策になりますが、できれば最大長のバリデーションと一意制約の両方の実施を推奨します。*)また、MySQLを使う場合でも、sql_modeにSTRICT_TRANS_TABLES等を指定する方法でも、列長を超えたINSERTをエラーにすることができます。MySQL5.6からこれがデフォルトになったとのことですが、私がテストに使用したUbuntu15.04ではMySQL5.6.24なのにstrictモードになっていなかったので、Linuxディストリビューションによる違いがあるかもしれません。ネットを検索すると、このデフォルト設定変更によりMySQL5.6でアプリが動かなくなったという報告を見かけるので、strictな方が安全であることは間違いありませんが、設定変更にあたってはテストを入念した方が良いと思われます。Truncation脆弱性について説明しました。前回のエントリで私は、「バリデーションの目的は、予期しない入力値によりデータベースの不整合その他の不具合を予防することにある」と書きました。Truncation攻撃であると言えます。これを防ぐ方法の一つとして、バリデーションはデータベースの不整合の発生が起きにくくする効果があり、結果としてセキュリティ上も有効です。それと同じように、一意性が要求されるデータベースカラムに一意制約を指定することも、データベースの不整合を起きにくくする効果があり、結果としてセキュリティ上の効果もあります。このように、バグの発生を防ぐためのプログラミング上の様々な施策には、一般的にセキュリティを高める効果があります。なんといっても脆弱性はバグの一種ですからね。言って、「一意制約の指定はセキュリティ対策です」と言われると、違和感を持つ人が多いのではないでしょうか。私が「バリデーションはセキュリティ対策である」という言葉に違和感があるのも同じ理由です。私は拙著P347に以下のように書きました。事例2:ユーザIDに一意制約をつけられないサイト筆者が脆弱性診断を担当したサイトで、特殊な操作により同一のユーザIDで複数のアカウントが作成できることが分かりました。サイト管理者に「テーブル定義でユーザIDの列に一意制約(UNIQUE)をつけた方がいいですよ」とアドバイスしましたが、ユーザの削除を論理削除(データベース上で削除フラグをつけて「消したことにする」こと)にしているので、一意制約はつけられないとのことでした。このようなサイトは他にもあると思われますが、アプリケーションのバグ(排他制御不備など)により、重複したユーザIDが登録される潜在的なリスクが残ります。事例1のように同一ユーザIDで別のアカウントが作成できると、誤って別ユーザとしてログインする可能性があります。データベース上でユーザIDを保存する列には、データベースの一意制約をつけることが望ましいでしょう。それができない場合、アプリケーション側でユーザIDの重複を防ぐ必要がありますが、その際は排他制御などに細心の注意を払ってユーザIDが重複しないように実装する必要があります。Truncationは、まさにログイン名の重複を意図的に作り出すという、データベースの不整合の悪用によるなりすまし手法と言えます。【HASHコンサルティング広告】HASHコンサルティング株式会社は、セキュリティエンジニアを募集しています。興味のある方は、twitterやfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。設定すれば問題がないようです。