php/MySQLによるログイン認証の仕組みとセキュリティ対策

このQ&Aのポイント
  • php/MySQLを使用したID/PWによるログイン認証のシステムを開発する際には、セキュリティ対策に注意が必要です。
  • 一般的にクッキーや暗号化を使用した認証方法は、盗聴やクッキーの改変によってセキュリティが脆弱になる可能性があります。
  • セキュアなログイン認証を実現するためには、セッション管理やハッシュ化などの技術を組み合わせることが重要です。
回答を見る
  • ベストアンサー

php/MySQLによるログイン認証について

お世話になります。 このたび、php/MySQLを使用したID/PWによる ログイン認証のシステムを開発しようとしています。 仕様としては1時間の自動ログイン機能付きです。 (1時間クッキーを有効にする) ネット各所で調べてみると 良く巷のWebやブログで紹介されているものは、 盗聴+クッキーの改変で容易に突破されそうに思います。 良く例にある、クッキーにID/PWを入れるものですが これでは盗聴とクッキー改変には耐えられそうもありません。 また非常に危険に思っています。 またPOSTしたID/PWをcrypt等で暗号化しても、 結局は暗号化したデータを盗聴されたら終わりな気がします。 何か良い仕組みがありましたら お教え願えれば光栄です。 よろしくお願いいたします。

  • PHP
  • 回答数3
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
  • BellBell
  • ベストアンサー率54% (327/598)
回答No.4

>それともフォーム送信後に >いちいち使用したセッション変数のみを >一つずつ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>

kayakiss
質問者

お礼

ご回答ありがとうございます。 なるほど!そのような方法があったのですね! 私が入門時に先輩から指導を受けた制作方法としては ----------------------------------------------------- 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']); ?> で入力済みの値を表示させるという構造でした。 これが当たり前になっていたために 余り他の方法を模索しようとも思っていませんでした。 もう少し、色々と効率的な方法を 模索して見たいと思います。 ありがとうございました。

その他の回答 (2)

  • 1minn
  • ベストアンサー率57% (52/90)
回答No.3

前の方も聞かれてますが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等で暗号化しても、結局は暗号化したデータを盗聴されたら終わりな気がします。 復号される前提の暗号はどこまで行っても安全ではないですよ。(不可逆でもそうですけどね) ある程度のセキュリティは保つべきですが、終りのない世界なので・・・

kayakiss
質問者

お礼

ご回答ありがとうございます。 > で、1時間の自動ログインというのはブラウザを閉じても有効なんですか? これはブラウザを閉じても有効と言うことになります。 お教えいただいた情報と、自分で調べた情報を参考に 初回ログイン時にランダム文字列のキーを作成し、それをDBに格納、 それをクッキーにも持たせて認証という方法で制作しました。 そのキーはブラウザを閉じてからの自動ログイン時に 再度書き換えられるように設定しました。 これでかなりパフォーマンスは上がったと思っています。 また問題になっていたセッションの問題ですが、 $tmp = $_SESSION[login]; session_destroy(); $_SESSION[login] = $tmp; 上記の方法で問題なく対応できています。 色々とご丁寧にありがとうございました。 奥の深い部分でこれがゴールと言うものはないと思いますが、 日々精進を続けてまいります。

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.2

>盗聴+クッキーの改変で容易に突破されそう まずはhttpsで処理することは前提でよいですね? クッキーの生存期間で時間を区切るのはNGです。 1時間と決めるのであれば、サーバー側でDBなりでユーザー管理が必須でしょう。 そのうえで、各ページにログイン情報のチェッカーを埋め込めば 最低限時間+ユーザーを指定したログインシステムは構築できそうです。 ただセッションハイジャックの問題などもあるので、 完璧にやりたいということであれば、より厳密な個体を判断するような 仕組みを組み込まなくてはいけません。

kayakiss
質問者

お礼

ご回答ありがとうございます。 当初はセッションによる管理を考えていましたが、 私のセッションに関する知識が乏しいため、 下記のような問題により、 ログイン認証ではセッションを使用していません。 ログインチェックで 例えば$_SESSION['login']に ログインチェック関係の変数を入れるとします。 これを使用したプログラムを全てのページに埋め込めば 確かにログインチェックができるかと思います。 ところがログイン後のページの各所で 登録フォームや送信フォームが多数あり、 その中で多数のセッション変数を使用しています。 それらのフォームの送信完了後に、 そのフォームで使用したセッション変数のみをクリアしたいのですが、 session_unsetやsession_destroyなどを使用すると、 ログインチェック用のセッション変数までクリアしてしまうため、 この辺りがうまくいかずにログイン認証にはセッションを使用していませんでした。 本題の質問とは外れてしまいますが、 ログインチェック用のセッションとその他のフォーム用のセッションに 分けて使用する方法はありませんでしょうか? それともフォーム送信後に いちいち使用したセッション変数のみを 一つずつunset($_SESSION['hoge']);する必要があるのでしょうか? もしそのようなことに関する情報がありましたら お教え願えれば光栄です。 ちなみに、ID/PWはcryptで暗号化して、 DBに格納されており、ログイン時のみ比較を行っています。

関連するQ&A

  • MySQLのログインを暗号化できますか?

    MySQLのログインを暗号化できますか? connectを張るときに"user id=○○; password=××; database=△△;Data Source=■■" をインターネット経由で送ってます。 この部分はオラクルだとデフォルトで暗号化されてるが、 MySQLでは平文のままだという話をききます。 1.平文のまま流れてるというのは本当なんでしょうか? 2.もし、平文のままなんだとすると、SSLみたく暗号通信化する方法は MySQL自体に実装されてるんでしょうか? それとも自前でトンネルを掘る必要があるんでしょうか? 平文のまま流れてるなら、いつかは盗聴されるように感じています。 上記について、ご存知の方おられましたらよろしくお願い申し上げます。

    • ベストアンサー
    • MySQL
  • PHP+mySQL認証画面

    サーバーの引っ越しで新しいサーバーにてプログラムの動作確認を行っています。 管理者パネルに入るのに、PHPで作成した認証プログラムでログインしようとすると、入力しても何度も聞いてきて入れません。 旧 MySQL5.0.22   phpMyAdmin2.8.2.4 新 MySQL5.1.69 phpMyAdmin3.5.8.1  IDとパスワードはデータベースで設定。 管理者パネルで変更できるようになっている。 $sv = "**"; $dbname = "**"; $user = "**"; $pass = "**"; ログイン認証 //データベースに接続する $conn = mysql_connect($sv,$user,$pass) or die("接続エラー"); mysql_select_db($dbname) or die("データーベース接続エラー"); $sql = "SELECT id, pass FROM pass_t WHERE pno=1"; $res = mysql_query($sql, $conn) or die("データ抽出エラー"); while ($row = mysql_fetch_array($res, MYSQL_ASSOC)) { $db_user_id=$row['id']; $db_password=$row['pass']; } if(!isset($_SERVER["PHP_AUTH_USER"]) || $_SERVER["PHP_AUTH_USER"] != "$db_user_id" || $_SERVER["PHP_AUTH_PW"] != "$db_password") { header("WWW-Authenticate: Basic realm=\"login\""); header('HTTP/1.0 401 Unauthorized'); echo "ユーザー名またはパスワードが間違っています。<br>"; echo "もう一度はじめからやり直してください。"; exit; } 細々変えて試してみましたが駄目でした。 まだまだわからないことだらけの初心者なので、どうにもならずで 解決策がありましたらぜひ教えて頂けますと幸いです。 よろしくお願いいたします。

    • 締切済み
    • PHP
  • ログイン認証ができません!!

    下記のようなメッセージが画面に書かれているのですが、クッキーを受け入れるにしてもログイン認証できないのですが、どのようにすればいいのでしょうか? ~メッセージ~ セッション管理にクッキーを使用しています。ブラウザがクッキーが受け入れるように設定してください。 ログイン後、サーバーとの無通信状態が一定時間続くか、ブラウザを終了すると自動的にログアウト処理されます。 パスワードを一定回数連続で間違えた場合、同一IPからの認証は一定時間はできなくなります。

  • サイトへの簡単で安全な認証方法について

    サイトへログインが楽に行えるように、 URLの引数に暗号キーをつけてログイン認証する 仕組みにしようかと考えているのですが、 そのようなログインは見たことがありません。 簡単にクラックされてしまうでしょうか? ログイン情報が同一サイトからPOST送信されたか 確かめるべきでしょうか? 1.URLだけで認証(ログインは楽) 2.POSTで認証&クッキー保存認証に対応 (ログインは楽) 2.の方がよさそうですが、クッキーは暗号化 しないと危険でしょうか?

  • PHPでcookieのみを使ったログインページ

    学校で「PHPでタイムカードを作成せよ」という課題がでました。 そこで、まずログインページを作ろうと思い、 検索をかけてサンプルプログラムを見たり、 分からない命令を調べてみたりしているのですが プログラミングが大の苦手でありまして・・ 残念なぐらいにわかりません。 実際に http://ml.php.gr.jp/pipermail/php-users/2004-July/023371.html にあったプログラムを動かしてみても、 ログインフォームの次のページ(認証ページ)で 「idが未入力です」と表示されてしまいます。 (idとpwは何度も確認して入力しています) どなたか簡単なログインページのサンプルを作っていただけないでしょうか 出来ればセキュリティー面などは考慮せずに、 クッキーのみを使った簡易なものをお願いしたいです。 それを拝見して勉強したいと思います・・ よろしくお願いします。

    • 締切済み
    • PHP
  • php sqlでログイン認証システムについてです。

    このようなソースを書いてログインシステムを書いています。 ここで接続はできたのですが、クエリーが失敗しましたと出てきます。 このソースをどのように修正すればよいのかアドバイスお願いできないでしょうか。よろしくお願いします。 <?php session_start(); $link = mysql_connect('localhost', 'root', 'root'); if (!$link) { die('接続失敗です。'.mysql_error()); } $db_selected = mysql_select_db('mydb', $link); if (!$db_selected){ die('データベース選択失敗です。'.mysql_error()); } mysql_set_charset('utf8'); // エラーメッセージの初期化 $errorMessage = ""; // ログインボタンが押された場合 if (isset($_POST["login"])) { // 1.ユーザIDの入力チェック if (empty($_POST["userid"])) { $errorMessage = "ユーザIDが未入力です。"; } else if (empty($_POST["password"])) { $errorMessage = "パスワードが未入力です。"; } // 2.ユーザIDとパスワードが入力されていたら認証する if (!empty($_POST["userid"]) && !empty($_POST["password"])) { // mysqlへの接続 $mysqli = new mysqli($db['localhost'], $db['root'], $db['root']); if ($mysqli->connect_errno) { print('<p>データベースへの接続に失敗しました。</p>' . $mysqli->connect_error); exit(); } // データベースの選択 $mysqli->select_db($db['mydb']); // 入力値のサニタイズ $userid = $mysqli->real_escape_string($_POST["userid"]); // クエリの実行 $query = "SELECT * FROM db_user WHERE name = '" . $userid . "'"; $result = $mysqli->query($query); if (!$result) { print('クエリーが失敗しました。' . $mysqli->error); $mysqli->close(); exit(); } while ($row = $result->fetch_assoc()) { // パスワード(暗号化済み)の取り出し $db_hashed_pwd = $row['password']; } // データベースの切断 $mysqli->close(); // 3.画面から入力されたパスワードとデータベースから取得したパスワードのハッシュを比較します。 //if ($_POST["password"] == $pw) { if (password_verify($_POST["password"], $db_hashed_pwd)) { // 4.認証成功なら、セッションIDを新規に発行する session_regenerate_id(true); $_SESSION["USERID"] = $_POST["userid"]; header("Location: main.php"); exit; } else { // 認証失敗 $errorMessage = "ユーザIDあるいはパスワードに誤りがあります。"; } } else { // 未入力なら何もしない } } ?>

    • 締切済み
    • PHP
  • ログイン時で、php+sessionについて

    普通のページは静的なhtmlなのですが、1ページだけログインページを付けています。 ログイン自体は問題ないのですが、普通のページは静的なhtmlなので、アカウントやパスは普通、データは渡せません。 できるのはphp+session(+javascipt)だけかな?と考えています。 1ページだけログインを付ける為にphpで作成しました。 問題は、html内にphp+sessionを使える方法を知りたいです。 IDやPASSの暗号化は分かっているので、その部分は今回スルーしてます。 変数名も書き方もバカなぐらい簡易化してます。 とにかくデータの渡し方を知りたいです。 ○test.html <form method="post" action="test.php"> <input type="text" name="id" id="id" value=""> <input type="text" name="pw" id="pw" value=""> <input type="submit" value="submit"> </form> ○test.php session_start(); session_name("id"); session_name("pw"); $_SESSION["id"]=$_POST["id"]; $_SESSION["pw"]=$_POST["pw"]; このIDとPASSをどうやったら、test.htmlのフォーム内に自動的に入れられるか、それがわかりません。 やっぱりjavascriptで、SESSIONを取得し、document.getElementByIdのinputか何かを使ってやるのでしょうか? 時間がないのですが、宜しくお願い致します。

    • ベストアンサー
    • PHP
  • 【PHP】Basic認証以外でメジャーな認証方法は?

    PHP歴1年、MySQL歴3ヶ月程度の職業プログラマなのですが、今回会員専用ページを作ることになり認証について勉強しています。 Basic認証より安全で「一般的な」認証方法は何でしょうか? 希望として、 ・Basic認証のようなポップアップウインドウは出したくない。  (教えてgooログインのような感じが理想) ・パスワードの送信は暗号化したい。 ・できればログアウトもしたい。 といった感じです。 環境は以下の通りです。 ・ファーストサーバー(レンタル) ・PHP5.2.6(Apache DSO) MySQL4.0.24 Linux 2.4.30 ・PEAR/シェル不可  1人でやっているため何が常識なのかわかりません。 お詳しい方、よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • gooメールのログインIDを記憶させたくない

    gooメールでログインIDとPWを記憶しないを選択し、またインターネットのプロパティでクッキーの削除をしても、ログインIDとPWが記憶されていてでてきてしまいます。どのようにしたら、表記されなくなるでしょうか。

  • phpとmysqlでログインページの作成

    phpとmysqlを使いMAMPでログインページの作成をしようと考えています。 idやpasswordなどはもうsqlに格納されている状態を想定しています。 そこで手順を知りたいのですがこれであっているでしょうか? dbに接続してidやpasswordなどをdbから引っ張ってきて取得する。 if文でsql上のidなどとログインページに入力した情報があっているかで条件わけをする。 合っていなければエラーメッセージを返す。合っていれば次のメイン画面に飛ばす。 初歩的な質問で恥ずかしいのですがdbの情報を取得するときは「mysql_fetch_assoc」関数でいいのでしょうか。 また、ログインページのサンプルを調べているとCookie版とSession版がありますがこの違いはCookieが一定時間情報を保持するのに対してSessionはブラウザなどを閉じるとリセットという解釈で間違いないでしょうか。 文がぐちゃぐちゃで申し訳ないのですが、お暇な時にでも回答お願い致します。

    • 締切済み
    • PHP

専門家に質問してみよう