2011-04-14

パスワード個人情報を扱うサービスを作る際に気をつけたこと

HTMLはわかるけど、サーバーサイドはお遊びでphpを触ったぐらいだったので、会員制でデータをためこむサイト作りに初めて挑戦した

今回重視したのは、「いか個人情報をお漏らししないようにして、万が一漏らしても被害を少なくするか」ということ。

世の中、有償サービスでもパスワードを平文で保存してるサービスが意外と多いらしいので、流出した時のリスクを少しでも減らせる対策として書きます

今回のシステム構成

サーバーロケットネットキャンペーンにでレンタルサーバ年1000円ポッキリプラン

クライアント側の処理HTML+CSS+jQuery(とプラグインもろもろ)
サーバ側の処理PHP
WebサーバーApache
データベースMySQL

個人情報こわい!

個人情報ビビる漏洩とかまじ困るし怒られるしこわい。

俺も巻き込まれたところでは、サミータウンがメールアドレスパスワードセットでお漏らししてお詫びに1ヶ月無料なにそれこわい

サミータウンだけならまだいいけど、メアドパスワードを他のサービスで共通化して使ってる情弱なので、

共通化してメアドパスワードをどこかのサービスが一箇所でも漏らすと、ヤフオクID乗っ取り事件みたいなことになる。

http://internet.watch.impress.co.jp/cda/news/2008/09/26/20967.html

だってできれば人様のメールアドレスパスワードとか預かりたくない。

万が一、肉親のメールドレス発見してパスワードにrapemeとか入ってたら明日からどういう顔すればいいかからない。

ググってみてもどこにも情報のってない。うーん困った。ダメもとで「個人情報ってどうやって保存したらいいんだろう。。。」

って、twitterでつぶやいたら、「住所とかは可逆暗号化でいいけど、パスワードハッシュで不可逆化しないとだめだよ!」

と、呪文のようなありがたい言葉を教えてもらった。

暗号化の種類

「住所とかは可逆暗号化でいいけど、パスワードハッシュで不可逆化しないとだめだよ!」

何のことかわからなったので、調べてみると、

・可逆暗号=元のデータに戻せる暗号化方式。

ハッシュハッシュ値を使った、元のデータに戻せない暗号化方式

うーん。。。よくわからん。。。

電話番号とか住所は、第三者が使用する情報なので、可逆が必要。パスワードは、認証しか使わないので、

ハッシュ値結果が一致すれば元のデータがわからなくてもOK、という方式なのでこういった暗号の使い分けをする。

●可逆暗号イメージ(もとにもどせる) 暗号キー開発者が指定する。
090-xxxx-xxxx →(暗号化)→ !'&%($% →(復号化)→ 090-xxxx-xxxxハッシュイメージ(もとにもどせない) 
登録passwordDBに保存)→(ハッシュ値抽出)→!"$#'$#="
ログインpassword →(ハッシュ値抽出)→!"$#'$#="
※二つのハッシュ値が合っていれば、パスワード一致として認証する。

暗号化の実現方法

可逆暗号電話番号とか住所とかに適用

今回はMySQL関数で実現した。encode関数暗号化して、decode関数でもとに戻す。

例えばtel_noという項目だけあるテーブルがあるとすると、

//データベースに保存する時
insert into テーブル名 (tel_no)  values (encode(tel_no,'暗号キー'));
//データベースから取得する時
select decode(tel_no,'暗号キー') from テーブル名;

これで、データベース格納時は暗号化(バイナリ化)されて、データベースから取り出してHTML表示する時に復号化はされる。

ハッシュパスワードかに適用

今回はphpのhash関数で実現した

ユーザ登録時>

$password=(フォームから取得)
$hash=hash('sha512',$password)
//ユーザ登録時は、ここで生成した$hashをデータベースにぶっこむ。

ユーザ認証時は、入力されたパスワードと、データベースパスワードが一致するかチェック。

ログイン認証時>

//フォームから入力されたパスワード
$input_password=(フォームから取得)
$input_hash=hash('sha512',$input_password);

//MySQLに保存されたパスワードを取得(略)
$db_hash==(データベースから取得)

//判定
if($input_hash==$db_hash)
	echo 'ログインしますよ!';
	//ここにログイン処理を書く
else
	die('メアドパスワードがあってないよ!');

これでもしSQLインジェクションとかでデータ流出しても、ハッシュ暗号パスワードに関してはまず解析されないはず。。。

可逆暗号データphp側の暗号キーが盗まれない限りバレない。。。はず。。。

暗号化する対象のデータをえらぶ

何でもかんでも暗号化するとコードが煩雑になるし、パフォーマンスにも影響でそうなので、

住所データ都道府県とか、漏れても良いような情報暗号しませんでした!!

本人が特定できなければ個人情報はないらしいので。。。

個人情報保護法
2条による定義個人情報」とは、生存する個人に関する情報であって、当該情報に含まれる氏名、生年月日その他の記述等により特定の個人を識別することができるもの(他の情報と容易に照合することができ、それにより特定の個人を識別することができることとなるものを含む。)をいう。

http://ja.wikisource.org/wiki/%E5%80%8B%E4%BA%BA%E6%83%85%E5%A0%B1%E3%81%AE%E4%BF%9D%E8%AD%B7%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E6%B3%95%E5%BE%8B#2

これで、もし漏れても、俺、ウンコ漏らして臭いけど、パンツから出てないからいいよね?というレベルはなった。はず。

お漏らさないようにキツくする

万が一漏れても大丈夫!と書いたけど、そもそも漏らすなというお話になる。色々調べた結果、以下の対策をほどこした

SQLインジェクション対策

・当初jQuery側でSQL組み立ててPHPに渡してたので、これだと任意のSQLが実行できて漏らし放題なのでやめる。

GETとかPOSTでDBに渡すパラメータを扱ってる場合、ちゃんとエスケープする。

例えばログイン認証するPHPで、GETメソッドでフォームからデータを取得するような場合

$id=$_GET['id']
$pwd=$_GET['pwd']
$sql="select * from ユーザーテーブル where uid='$id' and pwd='$pwd'

とかやってると、login.php?id=admin'&pwd=' OR '1'='1とかパラメータを渡されるとあら不思議

select *from ユーザテーブル where uid='root' and pwd='' or 1=1

で、誰でもログイン出来ちゃう!ので、mysql_real_escape_stringでエスケープしたり、渡されたパラメータが想定した値かどうか(例えば数値かどうか、とか)のチェックをいれたりする。

クロスサイトスクリプティング

・保存するデータタグJavascriptを埋め込まれないように、保存されたデータを出力する場合PHP側でhtmlspecialchars関数使ってエスケープするようにする。

こんな感じでお漏らし対策をした。間違いがあったら教えて欲しい

ちなみに出来上がったサイトはこれ。

http://oreni-makasero.com/

記事への反応(ブックマークコメント)

ログイン ユーザー登録
ようこそ ゲスト さん