- ベストアンサー
php/MySQLによるログイン認証の仕組みとセキュリティ対策
- php/MySQLを使用したID/PWによるログイン認証のシステムを開発する際には、セキュリティ対策に注意が必要です。
- 一般的にクッキーや暗号化を使用した認証方法は、盗聴やクッキーの改変によってセキュリティが脆弱になる可能性があります。
- セキュアなログイン認証を実現するためには、セッション管理やハッシュ化などの技術を組み合わせることが重要です。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
>それともフォーム送信後に >いちいち使用したセッション変数のみを >一つずつunset($_SESSION['hoge']);する必要があるのでしょうか? それが面倒だというなら、$_SESSIONに配列で放り込んでおけば? $_SESSION['hoge']=array('zip'='000-0000','tel'='090-0000-0000','name'='山田 太郎', 'address'='東京都港区○○1-1-1'・・・・・・・・・・・); ~~~~~~~~ unset($_SESSION['hoge']); データが1000種類あっても、一発です。 もっとも、送信フォームの内容のようなものをSESSIONに放り込むなんて事、普通はしませんけど。 自分自身にPOSTして、冒頭でPOSTか否かで送信処理か、送信フォームの表示かを判定(さらに、ワンタイムチケットでも設定しておけばなお良し)。 送信内容のエラーチェックをして(必須項目が入力されていないなど)、オールOKなら『送信しました』ページにリダイレクト、ダメならそのまま送信フォームを表示(その際にエラーメッセージを表示する)ってな感じですかね。 適当だけど、以下のような感じかな。 テストもしてないし、エラー処理もXSS対策も入れてないけど。 <?php $errors=array(); $hoge=''; $fuga=''; if (strtolower($_SERVER['REQUEST_METHOD'])=='post'){ if ($_POST['hoge']==''){ $errors['hoge_is_null']='HOGEが入力されていません'; }else{ $hoge=$_POST['hoge']; } if ($_POST['fuga']==''){ $errors['fuga_is_null']='FUGAが入力されていません'; }else{ $fuga=$_POST['fuga']; } if (0==count($errors)){ //送信処理 //送信完了ページにリダイレクト header("Location: ./send_complete.php"); } } ?> <html> ~~~ <body> <form action="" method="post"><!--actionを空白にすることで、自分自身に送信--> <input type="text" name="hoge" value="<?php echo $hoge;?>" /> <?php if (isset($errors['hoge_is_null'])){echo $errors['hoge_is_null'];}?> <input type="text" name="fuga" value="<?php echo $fuga;?>" /> <?php if (isset($errors['fuga_is_null'])){echo $errors['fuga_is_null'];}?> <input type="submit" value="送信" /> </form> </body> </html>
その他の回答 (2)
- 1minn
- ベストアンサー率57% (52/90)
前の方も聞かれてますがSSLなんですか? それであれば、盗聴に関してはそこまで意識する必要もなさそうな・・・ もちろん万全ではありませんが、そんな簡単に解析されるものではないですから で、1時間の自動ログインというのはブラウザを閉じても有効なんですか? (ブラウザって前提で聞いてますけど・・・) もしそうならcookie以外には識別不能になるので、cookieを使う必要はあると思います。 ただし、cookieにIDやらパスワードを入れるのは論外です。 やるのであれば、DBを使うようなので「ログイン中テーブル」のようなものをつくればよいのではないでしょうか。 ログイン認証を通過した時点でsession_idのような推測されないランダムな文字列をDBにINSERT。 それと同時にcookieにも同じ値をセットすれば認証済みという判定は出来ると思います。 よりデリケートにやるのであれば、キーと値のペアをどちらもランダムな値で持つのもいいと思いますし、通信のたびに値を書き換えるワンタイムトークンのような使い方もよいかもしれません。 他の方も回答されているとおり、cookieの生存時間だけではなく、「ログイン中テーブル」にデータをINSERT(UPDATE)した時間を持たせればそれで判定もできます。 > 本題の質問とは外れてしまいますが、ログインチェック用のセッションとその他のフォーム用のセッションに分けて使用する方法はありませんでしょうか? > > それともフォーム送信後にいちいち使用したセッション変数のみを一つずつunset($_SESSION['hoge']);する必要があるのでしょうか? > > もしそのようなことに関する情報がありましたら お教え願えれば光栄です。 SESSIONはそれなりに奥が深かったりもしますが、そんなにとっつきにくいものではないと思います。 よっぽどcookieよりも扱いやすいと私は思います。 $tmp = $_SESSION[login]; session_destroy(); $_SESSION[login] = $tmp; これじゃだめですか?というか $_SESSIONすべてを破棄する必要がないなら連想配列でわけるだけで済むと思いますが・・・ > またPOSTしたID/PWをcrypt等で暗号化しても、結局は暗号化したデータを盗聴されたら終わりな気がします。 復号される前提の暗号はどこまで行っても安全ではないですよ。(不可逆でもそうですけどね) ある程度のセキュリティは保つべきですが、終りのない世界なので・・・
お礼
ご回答ありがとうございます。 > で、1時間の自動ログインというのはブラウザを閉じても有効なんですか? これはブラウザを閉じても有効と言うことになります。 お教えいただいた情報と、自分で調べた情報を参考に 初回ログイン時にランダム文字列のキーを作成し、それをDBに格納、 それをクッキーにも持たせて認証という方法で制作しました。 そのキーはブラウザを閉じてからの自動ログイン時に 再度書き換えられるように設定しました。 これでかなりパフォーマンスは上がったと思っています。 また問題になっていたセッションの問題ですが、 $tmp = $_SESSION[login]; session_destroy(); $_SESSION[login] = $tmp; 上記の方法で問題なく対応できています。 色々とご丁寧にありがとうございました。 奥の深い部分でこれがゴールと言うものはないと思いますが、 日々精進を続けてまいります。
- yambejp
- ベストアンサー率51% (3827/7415)
>盗聴+クッキーの改変で容易に突破されそう まずはhttpsで処理することは前提でよいですね? クッキーの生存期間で時間を区切るのはNGです。 1時間と決めるのであれば、サーバー側でDBなりでユーザー管理が必須でしょう。 そのうえで、各ページにログイン情報のチェッカーを埋め込めば 最低限時間+ユーザーを指定したログインシステムは構築できそうです。 ただセッションハイジャックの問題などもあるので、 完璧にやりたいということであれば、より厳密な個体を判断するような 仕組みを組み込まなくてはいけません。
お礼
ご回答ありがとうございます。 当初はセッションによる管理を考えていましたが、 私のセッションに関する知識が乏しいため、 下記のような問題により、 ログイン認証ではセッションを使用していません。 ログインチェックで 例えば$_SESSION['login']に ログインチェック関係の変数を入れるとします。 これを使用したプログラムを全てのページに埋め込めば 確かにログインチェックができるかと思います。 ところがログイン後のページの各所で 登録フォームや送信フォームが多数あり、 その中で多数のセッション変数を使用しています。 それらのフォームの送信完了後に、 そのフォームで使用したセッション変数のみをクリアしたいのですが、 session_unsetやsession_destroyなどを使用すると、 ログインチェック用のセッション変数までクリアしてしまうため、 この辺りがうまくいかずにログイン認証にはセッションを使用していませんでした。 本題の質問とは外れてしまいますが、 ログインチェック用のセッションとその他のフォーム用のセッションに 分けて使用する方法はありませんでしょうか? それともフォーム送信後に いちいち使用したセッション変数のみを 一つずつunset($_SESSION['hoge']);する必要があるのでしょうか? もしそのようなことに関する情報がありましたら お教え願えれば光栄です。 ちなみに、ID/PWはcryptで暗号化して、 DBに格納されており、ログイン時のみ比較を行っています。
お礼
ご回答ありがとうございます。 なるほど!そのような方法があったのですね! 私が入門時に先輩から指導を受けた制作方法としては ----------------------------------------------------- index.php...フォームページ(入力確認含む) ses_index.php...入力チェック~送信・DB入力処理 index_end.php...入力完了画面 ----------------------------------------------------- の三部構成で制作を進め、 index.phpからses_index.phpへPOSTした際に $_SESSION['hoge'] = $_POST['hoge']; とPOSTした変数をセッションに格納し、 入力チェックに引っ掛かった変数については、 include("index.php"); でindex.phpにエラー内容を表示させて 入力を済ませていたフォームは value = "<?php print($_SESSION['hoge']); ?> で入力済みの値を表示させるという構造でした。 これが当たり前になっていたために 余り他の方法を模索しようとも思っていませんでした。 もう少し、色々と効率的な方法を 模索して見たいと思います。 ありがとうございました。