MySQL暗号化(AES_ENCRYPT,AES_DECRYPT)について

セキュリティに関してどんどん厳しくなっている今日この頃。
DBの暗号化を求められることも少なくない。
というか漏えいしたらこっちにだってリスクがふりかかるので、正直全力でセキュリティ対策はやっておきたい。
(だからもっと予算を割いてくれ!どうしてそこから削ろうとするんだ!)


MySQL 暗号化」で検索すると「AES_ENCRYPT,AES_DECRYPT」この二つの関数が引っかかる。

SELECT AES_ENCRYPT('kan naoto','password');

と打ち込むと、環境にもよるけど暗号化されているのが分かる。(貼れるかな)

                                                                            • +
AES_ENCRYPT('kan naoto','password')
                                                                            • +
ウMァ9\\Kォ5F・
                                                                            • +

1 row in set (0.00 sec)

文字化けしているのは、暗号化されてバイナリ型になっているから。
この値をいつもと同じようにvarchar型とかtext型にINSERTしようとすると怒られてしまう。
ではどういう型にすればよいのか?
MySQLのマニュアルではBLOB型に保存しろ、と書いてあるけど、、全部BLOB型にするのってまずくない?
MySQLには「11個以上のBLOB/TEXT/VARCHAR(768バイト以上)を作成すると合計で8KBを超えてしまうので「最大行サイズ8KBまで」制限に引っかかる」というトラップもあるので、全部BLOB型!は、避けたいところ。

日本人のサイトだと「文字化けして見れないのでHEXをかませましょう」、と書いてあるけれど
HEX(AES_ENCRYPT(...))って美しくないと思うんだけどな。
だいたい暗号化してるんだから文字化けして見れなくて当然じゃん...何をしたいのよ...何のために16進数にするんだ...
私の理解がおかしいのかな...


で、とある海外サイトを見るとVARBINARYというものを使えと出ていた
VARBINARYはVARCHARのBINARY版?で、VARCHA(100)のカラムを暗号化するなら、VARBINARY(200)。
約2倍の容量をみておけばよいみたい。
これは、文字列を暗号化した際の長さが、

16 × (trunc(string_length / 16) + 1)

という式で表されるからで、

= 16 * (trunc(100/ 16) + 1)
= 16 * (6.25 + 1)
= 16 * 7.25
= 116

↑200もあれば十分だろう、とのこと。


さて、暗号化したはよいが、その中に検索したい項目があった場合どうすればよいのか。
名前とメールアドレスを登録したテーブルがあって、名前で検索してその人のメールアドレスを知りたい!みたいな場合。

どっかのサイトで、下記のようなSQLを書いている奴がいた。

SELECT id, AES_DECRYPT(name,'password'), AES_DECRYPT(email,'password') FROM t_test
WHERE name = AES_DECRYPT('naoto','password');

んで、これだとLIKE検索が出来ないー><ってなってる人、、、私にとってはこの発想がなかったYO

SELECT id, AES_DECRYPT(name,'password'), AES_DECRYPT(email,'password') FROM t_test
WHERE AES_DECRYPT(name,'password') LIKE '%naoto%';

で、いいじゃん。
ただINDEXが使われないので、件数が多くなったときどうするか、だな〜