簡単なセキュリティ対策をしながらIDとPasswordを登録する方法
使う目的
- ユーザの登録を必要とした環境で、何も考えずにサクッと書きたい
- セキュリティは必要最低限の対策をしたいけど、面倒な実装はしたくない
- どんなユーザ管理をするにしても基本の書き方なので備忘録兼
環境
php5 + apache2
MySQL5.6
方針
- IDは英数字のみ有効、PasswordはHash化する
- IDとHashedPasswordをデータベースに書き込む
- それを用いてユーザ認証を行う
免責
セキュリティ上問題がある記述をしている場合もあります。そのまま使用して問題が起こった場合でも責任は負えません。
IDとPasswordを処理する
POSTメソッドでid, pswdを受け取って
<?php mb_language("ja"); mb_internal_encoding("UTF-8"); header('X-FRAME-OPTIONS:DENY'); $r = rand(1000,9999); if(!isset($_POST['id'], $_POST['pswd']){ //Parameter Manipulation対応 die(""); } //英数字以外の撃ち落とし(簡易版) //XSS, SQL Injection対応 $userid = mb_ereg_replace("/[^0-9a-zA-Z]/", "", $_POST['id']); //不正な文字があった場合別の処理を行う if($userid === $_POST['id']){ die(""); } $hashedPswd = sha1($r.$userid.$_POST['pswd']."^v^Teeeeemo^v^"); ?>
DBに書き込み
実際に使用する場合は先頭のdefineを書き換えて下さい
<?php //ひとつ前の$r, $hashedPswd, $useridを使用します //この辺を書き換えて使ってね define('SQL_HOST', "localhost"); //SQLホスト名 define('SQL_USER', "root"); //SQLユーザ名 define('SQL_PSWD', "pswd"); //SQLパスワード define('DB', "dbName"); //データベース名 define('TABLE', "tableName"); //テーブル名 //登録するときに発行するQuery $regQuery = "INSERT INTO ". DB . "." . TABLE; $regQuery .= "(`r`, `userid`, `hashedPswd`) "; $regQuery .= "VALUES ('". $r . "', '" . $userid . "', '" . $hashedPswd . "')"; //すでに登録されているかどうかを確認するQuery $chkQuery = "SELECT * FROM `". TABLE . "` WHERE `userid` = '" . $userid . "'" ; //SQL接続開始 $sqlLink = mysqli_connect(SQL_HOST, SQL_USER, SQL_PSWD); if(!$sqlLink){die("");} mysqli_set_charset($sqlLink, "utf8"); if(mysqli_select_db($sqlLink, DB)){die("");} //SELECT→fetchしてみてNULLでないなら存在するuserid $sql_result = mysqli_query($sqlLink, $chkQuery); if(mysqli_fetch_row($sql_result) != NULL){ die("登録済みのID"); } //登録を行う mysqli_query($sqlLink, $regQuery); ?>
認証を実際に行う
POSTでidとpswdを受け取ってから動作。$rはデータベースから読み出し。
<?php //ログインに成功したユーザ名は$logonUserに返却される。NULLならログイン失敗。 $logonUser = NULL; define('SQL_HOST', "localhost"); //SQLホスト名 define('SQL_USER', "root"); //SQLユーザ名 define('SQL_PSWD', "pswd"); //SQLパスワード define('DB', "dbName"); //データベース名 define('TABLE', "tableName"); //テーブル名 //入力されたuserid, pswdを登録時とおなじ手順を踏んでcheck //英数字以外の撃ち落とし(簡易版) //SQL Injection対応 $userid = mb_ereg_replace("/[^0-9a-zA-Z]/", "", $_POST['id']); //useridをSELECTし正解のデータを受け取るQuery $sltQuery = "SELECT * FROM `". TABLE . "` WHERE `userid` = '" . $userid . "'" ; //SQL接続開始 $sqlLink = mysqli_connect(SQL_HOST, SQL_USER, SQL_PSWD); if(!$sqlLink){die("");} mysqli_set_charset($sqlLink, "utf8"); if(mysqli_select_db($sqlLink, DB)){die("");} $sqlResult = mysqli_query($sqlLink, $sltQuery); $userData = mysqli_fetch_array($sqlResult); mysqli_free_result($sqlResult); mysqli_close($sqlLink); //登録時と同じ方法でパスワードを認証 $challengePswd = sha1($userData['r'].$userid.$_POST['pswd']."^v^Teeeeemo^v^"); if($challengePswd === $userData['pswd'] && $userid === $userData['userid']){ $logonUser = $userData['userid']; }else{ $logonUser = NULL; } ?>
備考
- PHP: password_hash - Manualによるとsha1等による自前での認証よりも優れている、Passwordをハッシュ化するための関数があるようです。
- 同様に、PHP: password_verify - Manualの関数で認証も可能なようです。
- 文中に出る"^v^Teeeeemo^v^"は固定文字列で、ハッシュ化される前の文字列を推測することが困難になるように付与しています。ハッシュとソルト、ストレッチングを正しく理解する:本当は怖いパスワードの話 (3/4) - @IT
- $rについても同様です。
- もしかして:ティーモ(Teemo) - LoLJPWiki
- $rについても同様です。