DBに保存する時に個人情報をそのまま保存するのは、万が一DBの情報が流出した時にまずいので、色々と調べてみました。
まず、パスワードはphpのmd5でハッシュ化して保存すれば、復号できないのでOK、パスワードを忘れた場合は、新しいパスワードをランダム生成。
次に、暗号・復号するデータ。
氏名やメールアドレスなど、
php側で暗号・復号する方法と、DB側で暗号・復号する方法があります。(ハードディスク自体暗号の方法もありますが)
で、問題は、LIKE検索とINDEXでした。
基本、暗号化して保存すると上記2点が出来なくなることが問題です。
その点も踏まえてどんな方法があるか調査してみました。
とりあえず今回は
php mysqlの環境で出来ればということで・・・
php側で暗号化・復号
・mcrypt拡張モジュールを使った暗号化
・openssl拡張モジュールを使った暗号化
linuxにパッケージをインストールする必要がある。レンタルサーバーで使用できない場合があるので今回は調査しませんでした。
・PEAR::Crypt_Blowfishを使った暗号化
これはレンタルサーバーでも設置できるので、調査しました。
8バイトごとに暗号化していくみたいで足りない場合は¥0が後ろに足されます。なので、復号時はrtrimで後ろの¥0を取る必要あり。
完全一致検索では、検索でき、INDEXも効きますが、LIKE検索は無理でした。(8バイトごとに暗号化してるので当然ですね・・・)
メールアドレス等の完全一致検索しかしないフィールドであれば有効です。
下記サンプルコード
// Crypt_Blowfish 暗号化キーと初期化ベクトル(8byte文字列) define('CBF_KEY' , 'abc' ); define('CBF_IV' , '12345678' ); // 暗号化--------------------------- // CBCにて暗号化(キーと初期化ベクトルを引数に与える) $blowfish = Crypt_Blowfish::factory( 'cbc', CBF_KEY, CBF_IV ); $address = $blowfish->encrypt( $address ); // このままだとバイナリデータなのでbase64で文字列化 $address = base64_encode( $address ); // 復号--------------------------- // 復号したいパスワード $address = base64_decode( $address); // ←バイナリへ戻す // CBCにて復号化(キーと初期化ベクトルを引数に与える) $blowfish = Crypt_Blowfish::factory( 'cbc', CBF_KEY, CBF_IV ); $address = rtrim($blowfish->decrypt( $address ),"\0"); // 検索は暗号化して検索してください。
DB側で暗号化・復号
MySQLのAES_ENCRYPT・AES_DECRYPT
MySQL標準でついている暗号化関数です。
AES_ENCRYPT・AES_DECRYPTだけでは、バイナリになってしまうのでHEXという関数で16進数化して保存します。
LIKE検索が出来ますが、DB内部で復号して検索してるみたいで、INDEXは効きませんでした。
氏名や住所等のフィールドで有効だと思います。
下記サンプルコード
// 「ans_key」は任意の暗号キー // 登録する時 INSERT INTO users (address) values (HEX(AES_ENCRYPT('大阪市','ans_key'))); // 検索する時 SELECT *,AES_DECRYPT(UNHEX(address),'ans_key') as ad FROM users WHERE AES_DECRYPT(UNHEX(address),'ans_key') LIKE '大阪%';
今回、色々調査してみましたが、LIKE検索、INDEX両方とも使えるのは見つけられませんでした。何かいい方法ないかな?(PEAR::Crypt_Blowfishで文字列1文字ずつやればLIKE検索できるだろうけど、文字数が多くなりすぎるし・・・)