DB暗号化を調べてみた

| トラックバック(0)
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検索できるだろうけど、文字数が多くなりすぎるし・・・)

トラックバック(0)

このブログ記事を参照しているブログ一覧: DB暗号化を調べてみた

このブログ記事に対するトラックバックURL: http://www.okushin.co.jp/mt_co_jp/mt-tb.cgi/132