パスワードをデータベースに保存するときは、一緒に塩を入れよう
セキュアに保存する -> 漏れた場合を想定する
データベース(以下DB)にパスワードを保存するとき、そのまま
(平文で)保存してはいけません。データが漏れた場合に、パスワードが
見た瞬間わかってしまうからです。
パスワードを保存する場合、暗号化してからDBへインサートします。
実装例
手法は多種多様ですが、ここではSALTを使って暗号化
してみたいと思います。PHP + MySQLでの想定です。(ちなみにPDO)
SALTはランダムな文字列で、各ユーザごとにそれぞれ異なる
ものを用意します。
<?php /* 暗号化関数 */ function saltAngo($password, $salt) { $saltPassword = crypt($password, $salt); return $saltPassword; } /* ランダムな文字列を生成 */ function mkSalt($length = 8) { return substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyz', $length)), 0, $length); }
<?php /* 上記ファイルの関数をrequire_onceなどで使えるようになっているとします。 */ $user = 'hoge'; $password = 'hogehoge'; $stmt = $pdo->prepare('INSERT INTO userdata SET user = ?, password = ?, salt = ?'); // トランザクション開始 $pdo->beginTransaction(); try { $stmt->bindValue(1, $user); $salt = mkSalt(); // ランダムな文字列作成 // パスワードはsaltAngo関数で暗号化 $password = saltAngo($password, $salt); $stmt->bindValue(2, $password); $stmt->bindValue(3, $salt); // 使ったSALTもDBへ保存 $stmt->execute(); // コミット $pdo->commit(); } catch (PDOException $e) { // エラーでロールバック $pdo->rollBack(); throw $e; }
ログイン時は、DBに保存された同じSALTを使います。同じ暗号化のロジックを使用すれば、同じ結果が
戻ってくることを利用するのです。
<?php /* 実際はちゃんと無毒化しましょう */ $user = $_POST['user']; $password = $_POST['password']; $stmt = $pdo->prepare('SELECT * FROM userdata WHERE user = ?'); $stmt->bindValue(1, $user); $stmt->execute(); $row = $stmt->fetch(PDO::FETCH_ASSOC); if (!empty($row)) { $salt = $row['salt']; $password = crypt($password, $salt); // 保存時と同じSALTで復号化 // パスワードが一致しているか if ($row['password'] === $password) { echo 'ログイン完了'; } else { echo 'ユーザ名かパスワードが違います'; } } else { echo 'そのようなユーザは登録されていません'; }
ここでは説明を簡単にするため、弱い暗号化で済ませています。実際には、もっと
強いロジックを考えましょう。