Posted on

DB暗号化を調べてみた

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バイトごとに暗号化してるので当然ですね・・・)
メールアドレス等の完全一致検索しかしないフィールドであれば有効です。
下記サンプルコード

  1. // Crypt_Blowfish 暗号化キーと初期化ベクトル(8byte文字列)  
  2. define('CBF_KEY' , 'abc' );  
  3. define('CBF_IV' , '12345678' );  
  4. // 暗号化---------------------------  
  5. // CBCにて暗号化(キーと初期化ベクトルを引数に与える)  
  6. $blowfish = Crypt_Blowfish::factory( 'cbc', CBF_KEY, CBF_IV );  
  7. $address = $blowfish->encrypt( $address );  
  8. // このままだとバイナリデータなのでbase64で文字列化  
  9. $address = base64_encode$address );  
  10. // 復号---------------------------  
  11. // 復号したいパスワード  
  12. $address = base64_decode$address); // ←バイナリへ戻す  
  13. // CBCにて復号化(キーと初期化ベクトルを引数に与える)  
  14. $blowfish = Crypt_Blowfish::factory( 'cbc', CBF_KEY, CBF_IV );  
  15. $address = rtrim($blowfish->decrypt( $address ),"\0");  
  16. // 検索は暗号化して検索してください。  
DB側で暗号化・復号
MySQLのAES_ENCRYPT・AES_DECRYPT
MySQL標準でついている暗号化関数です。
AES_ENCRYPT・AES_DECRYPTだけでは、バイナリになってしまうのでHEXという関数で16進数化して保存します。
LIKE検索が出来ますが、DB内部で復号して検索してるみたいで、INDEXは効きませんでした。
氏名や住所等のフィールドで有効だと思います。
下記サンプルコード

  1. // 「ans_key」は任意の暗号キー  
  2. // 登録する時  
  3. INSERT INTO users (address) values (HEX(AES_ENCRYPT('大阪市','ans_key')));  
  4. // 検索する時  
  5. SELECT  
  6. *,AES_DECRYPT(UNHEX(address),'ans_key'as ad FROM users  
  7. WHERE  
  8. AES_DECRYPT(UNHEX(address),'ans_key') LIKE '大阪%';  
今回、色々調査してみましたが、LIKE検索、INDEX両方とも使えるのは見つけられませんでした。何かいい方法ないかな?(PEAR::Crypt_Blowfishで文字列1文字ずつやればLIKE検索できるだろうけど、文字数が多くなりすぎるし・・・)