CakePHPで個人情報をDBに保存する際に、暗号化しておく話。

前置き

ひっそりとClosedオープンしたECサイト。
ECなだけに、住所や電話番号等の個人情報をデータベースに保存する必要があります。
(クレジットカード情報は基本的にはカード決済会社に投げてて自社では保存しない ※正確には一時的にセッションとして保持はしているが)

これらの情報を最初は平文でデータベースに保存していたんだけど、途中から暗号化して保存するようにしました。
理由はなんらかの攻撃(例えばSQLインジェクションとか)をうけてデータベースを直接いじられる状況に陥っても、大事なデータは暗号化されているのでわからないからです。いや、まあその状況すでにマズイやん……というツッコミはあるかと思われますが……笑
ソースコード中の暗号・復号キーも流出するとアウトです。
二段構えの防御していて損はないですよね。
(これでもけっきょく、莫大な演算能力を使用すればいつかは復号化されちゃうんだけど……いろいろ対応をする時間稼ぎにはなりますよね。復号化される前に犯人を始末すればなんとかなります。え。)

私が普段使っているCakePHPでは下記のようにして実装している。

暗号化・復号化ライブラリをVendorあたりに作っておく

Modelとかビヘイビアとかに実装してもいいんだけど、なんだかんだで状況に応じてControllerで使用することもあるので、どこからでも呼び出せるようにVendorあたりにCryptクラスを実装しておく。
こんな感じです。

encryptメソッドが暗号化、decryptメソッドが復号化です。
実際の暗号化にはCakePHP内にあるSecurity::rijndaelを利用します。
Security::rijndaelは確かCakePHP2.2くらいから追加されている気がする。
使用するにはphp-mcryptがインストールされている必要があります。
中身のソースを読んでみたけど、一般的にベストプラクティスとされている実装がしてあるので大丈夫だと思う。
(ちゃんとCBCモードも使用しているので暗号化されたバイナリが毎回違うものになってくれます。なので推測もされにくい)

似たようなメソッドとして、Security::cipherっていうのもあるんだけど、rijndaelが使用できるならrijndaelを使用することをオススメします。
というのも、実装を見てみたら普通にXOR暗号を使用している。もちろんキーはいれてるけど、それでもちょっとなー……脆弱じゃないのコレ…。

Configure::read(‘constants.crypt_key’)ってやつは、Configureで定義している暗号・復号キーです。
こいつをどっか別ファイルで定義しておきましょう。
本番環境とテスト環境でこのキーを違うの使うのもいいかもしれませんね。
最近入りたてのエンジニアが実は競合他社のスパイでした!なんてことがあるかもしれませんし(いや、ねーだろ……)、本番環境のキーはリードエンジニアな人がしっかり管理する。
うちの会社は、サーバーサイドエンジニア2人しかいないので、まだいいや……。
求むサーバーサイドエンジニア。

話しを戻します。
encryptされるのはバイナリデータなので、このままだとデータベースに保存できません。
なので、Base64エンコードしてデータベースに保存できるようにしましょう。そのため、base64_encode関数を使用しています。
(代わりにbin2hex, packのコンボでもいいかもしれない。)

モデルのbeforeSaveにて保存する前に暗号化する

さて、実際に保存する前に暗号化します。
この手の処理はbeforeSaveあたりに実装しておくと便利ではなかろうか。
(usersテーブルに保存するなら、UserモデルのbeforeSaveに実装する)

先ほど作成したCryptクラスを使用します。
あ、ソースコードのどっかでApp::uses(‘Crypt’, ‘Vendor’);を実行しておくこと。

この例ではデータベースに保存するときに、名前と住所を暗号化してから保存しています。
CBCモードで暗号化しているので、ちゃんと毎回生成される文字列が違うので、推測されにくくなっています。

モデルのafterFindで復号化する

DBから値をとってくる度に復号化するのはとても面倒です。
こういった処理はafterFindに実装する。
今回は暗号化のときと違ってAppModelのafterFindに実装しておきます。
(UserモデルのafterFindだと、状況によっては実行されない場合があるので。)

あ、こっちもソースコードのどっかでApp::uses(‘Crypt’, ‘Vendor’);を実行しておくこと。
findしたUserの中のnameとaddressは、これで勝手に復号化してくれます。
わーいわーい!

デメリット

・当然、暗号化・復号化するのでその分無駄な処理が走りますよね。。
・キーをなくしたら詰む。その時は土下座じゃすまなくなる。

さいごに

本スクリプトによって生じるいかなる問題に対して、私は責任を負いません。
だって僕は悪くないんだか(ry 球磨川ぁああ!
めだかボックス最新巻の不知火VS球磨川戦は良かったねー……。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">