SSL/SSHによってクライアント/サーバー間で通信されるデータは保護されますが、 データベースに保存されたデータは保護されません。SSLはあくまで通信上の プロトコルなのです。
一旦アタッカーがデータベースへ(ウェブサーバーを通さずに)アクセスできてしまうと、 そこに格納されているデータ自体が暗号化されていない限り、自由に閲覧され、 使用されてしまいます。データを暗号化することによって、この脅威を減らすことが できますが、この機能をサポートしているデータベースは僅かです。
この問題への最も簡単な対応策は、まず自分専用の暗号化パッケージを作成し、 それをあなたのPHPスクリプトから使用することです。PHPのMcrypt, Mhash といった幾つかの拡張モジュールは、様々な暗号化アルゴリズムをサポート しているので役に立つでしょう。データ格納時に暗号化を行い、取得時に 復号化します。この方法についてはリファレンスを参照してください。
もし完全にデータを隠したい場合や、元のデータ自体は必要ない場合(つまり 表示されない場合)は、ハッシュも考慮に入れたほうが良いでしょう。 ハッシュの良く知られた使用方法は、パスワードをそのまま格納せずに、 その暗号学的ハッシュ値を格納する方法です。
PHP 5.5 以降には password 関数があり、 機密データをハッシュしたりそのハッシュを扱ったりする便利な仕組みが用意されています。 PHP 5.3.7 以降では » password_compat ライブラリも使えます。
password_hash() は、その時点で最も強力なアルゴリズムを使って、 与えられた文字列をハッシュします。また password_verify() は、与えられたパスワードのハッシュがデータベース内のハッシュと一致するかどうかを調べます。
例1 ハッシュされたパスワードフィールド
<?php
// ハッシュされたパスワードを格納する
$query = sprintf("INSERT INTO users(name,pwd) VALUES('%s','%s');",
pg_escape_string($username),
password_hash($password, PASSWORD_DEFAULT));
$result = pg_query($connection, $query);
// パスワードが正しいかどうか問い合わせる
$query = sprintf("SELECT pwd FROM users WHERE name='%s';",
pg_escape_string($username));
$row = pg_fetch_assoc(pg_query($connection, $query));
if ($row && password_verify($password, $row['pwd'])) {
echo 'Welcome, ' . htmlspecialchars($username) . '!';
} else {
echo 'Authentication failed for ' . htmlspecialchars($username) . '.';
}
?>
古いバージョンの PHP で同じことを実現するには crypt() 関数を使用します。
例2 crypt() によるパスワードのハッシュ
<?php
// ハッシュされたパスワードを格納する
// $random_chars retrieved e.g. using /dev/random
$query = sprintf("INSERT INTO users(name,pwd) VALUES('%s','%s');",
pg_escape_string($username),
pg_escape_string(crypt($password, '$2a$07$' . $random_chars . '$')));
$result = pg_query($connection, $query);
// パスワードが正しいかどうか問い合わせる
$query = sprintf("SELECT pwd FROM users WHERE name='%s';",
pg_escape_string($username));
$row = pg_fetch_assoc(pg_query($connection, $query));
if ($row && crypt($password, $row['pwd']) == $row['pwd']) {
echo 'Welcome, ' . htmlspecialchars($username) . '!';
} else {
echo htmlspecialchars($username) . 'の認証が失敗しました。';
}
?>