徳丸さんのスライド「いまさら聞けないパスワードの取り扱い方」に見られるように、昨今、ウェブアプリケーションの設計要件として、サーバ内に侵入された場合でもユーザーのパスワードをできるだけ保護すべきという論調が見受けられるようになってきました。上掲のスライドでは、その手法としてソルトつきハッシュ化を勧めています。スライドに書かれているとおり、ソルトつきハッシュには、複雑なパスワードの解読は困難になるものの、単純なパスワードを設定してしまっているユーザーのパスワードについては十分な保護を提供できないという問題があります。多くのユーザーは適切なパスワード運用ができない、というのが悲しい現実です。ソルトつきハッシュを使った手法でこのような問題が残るのは、ウェブアプリケーションサーバに侵入した攻撃者がユーザーの認証情報をダウンロードして、認証情報をオフライン攻撃することを防ぎようがない、という前提を置いているからです。逆の言い方をすると、攻撃者がアプリケーションサーバに侵入したとしてもユーザーの認証情報にアクセスできなければ、認証情報を奪われる可能性はないわけです。そのようなシステムを構築するにはどのようにしたらいいでしょうか。一般的なウェブアプリケーションにおける答えは、ストアドプロシージャの利用とデータベースサーバの保護にあります注1。多くのSQLデータベースサーバはストアドプロシージャとストアドファンクションをサポートしており、これはMySQLやPostgreSQLといったオープンソースRDBMSでも例外ではありません。ストアドプロシージャやストアドファンクションには二つの役割があり、ひとつは処理手順をまとめること、もうひとつは、テーブルへのアクセスパターンを限定することです。MySQLの場合、以下のようなDDLを実行することで、一般ユーザー権限(webapp)からは読み書きできない認証情報カラムpasssalt(ソルト値を格納)とpasshash(ハッシュ値を格納)をもつuserテーブルを作ると同時に、パスワードの一致を確認するストアドファンクション(check_pw)を提供することができます。webapp@'webapp-host';実際に、このデータベースに一般ユーザー権限で接続してみると、以下のように、ユーザーの作成はできるものの認証情報は読めない一方で、パスワードの検証は可能、となっていることがわかります。sec)このように、SQLデータベース内にパスワードの検証/更新ロジックを持たせることで、(データベースに一般ユーザー権限でアクセスするための情報が保存された)ウェブアプリケーションサーバに攻撃者の侵入を許した場合でも、パスワードの漏洩を防ぐことができます。ストアドプロシージャで監査ログを出力することで、攻撃を検知したり被害範囲を特定したりといったことも可能になるでしょう。このような手法を実践するにあたっては、@isidaiさんの指摘をあわせて参照の上、各自の責任において設計、実装くださいますようお願いいたします)■■データベースサーバの保護SQLデータベースの機能を利用してパスワードを保護する場合に考えなければならないこととして、ウェブアプリケーションサーバが攻撃者の手に落ちた場合に、そこを踏み台としてデータベースサーバに侵入されるリスクを下げるにはどうすれば良いか、という点があります。答えは単純で、データベースサーバをウェブアプリケーションサーバとは別のネットワークセグメントに配置し、両者の間にファイアウォールを設置すれば良い注2、ということになります。ファイアウォールの役割は、ウェブアプリケーションサーバからデータベースサーバへのアクセスを正規のTCPポートを指定するもの以外、全て遮断することです注3。このように設定することで、データベースサーバの権限管理機能にバグがない限り、ウェブアプリケーションサーバを踏み台として認証情報を奪われる可能性はなくなります。言うまでもありませんが、データベースサーバを配置するネットワークセグメントをインターネットと直接接続してはいけません。理想的には、アクセス手段を厳密に規定して管理系セグメントからのみ接続可能とすべきでしょう。■■まとめユーザーのパスワードを適切に暗号化することは重要ですが(そのまとめとして徳丸さんのスライドは優れていると思います)、サーバへの侵入を前提としてアーキテクチャを設計する際には、多層防御の手法が有効になります。本稿では、RDBMSサーバのストアドプロシージャとファイアウォールの使用を通じて、ユーザーの認証情報を多層防御するウェブアプリケーションが簡単に構成できることを説明しました。実は、本稿で取り上げた問題とその解は、Unixにおいてシャドウパスワードが導入された経緯の変奏曲です。Unixのシャドウパスワードとは、誰もが閲覧可能なファイル(/etc/passwd)に一方向暗号化(ハッシュ化)されたパスワードを記載しておくのではなく、攻撃者(一般ユーザー)がアクセスし得ないファイル(/etc/shadow)に認証情報を配置し、認証が必要な場合はAPIを通してルート権限で動作するプロセスに問い合わせ、/etc/shadowの内容と比較した結果を回答してもらう、という仕組みです。