最新閲覧日:

お世話になります。

このたび、php/MySQLを使用したID/PWによる
ログイン認証のシステムを開発しようとしています。
仕様としては1時間の自動ログイン機能付きです。
(1時間クッキーを有効にする)

ネット各所で調べてみると
良く巷のWebやブログで紹介されているものは、
盗聴+クッキーの改変で容易に突破されそうに思います。

良く例にある、クッキーにID/PWを入れるものですが
これでは盗聴とクッキー改変には耐えられそうもありません。
また非常に危険に思っています。

またPOSTしたID/PWをcrypt等で暗号化しても、
結局は暗号化したデータを盗聴されたら終わりな気がします。

何か良い仕組みがありましたら
お教え願えれば光栄です。

よろしくお願いいたします。

このQ&Aに関連する最新のQ&A

A 回答 (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>
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
なるほど!そのような方法があったのですね!

私が入門時に先輩から指導を受けた制作方法としては
-----------------------------------------------------
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']); ?>

で入力済みの値を表示させるという構造でした。

これが当たり前になっていたために
余り他の方法を模索しようとも思っていませんでした。

もう少し、色々と効率的な方法を
模索して見たいと思います。

ありがとうございました。

お礼日時:2011/11/03 20:21

前の方も聞かれてますが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等で暗号化しても、結局は暗号化したデータを盗聴されたら終わりな気がします。

復号される前提の暗号はどこまで行っても安全ではないですよ。(不可逆でもそうですけどね)
ある程度のセキュリティは保つべきですが、終りのない世界なので・・・
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
> で、1時間の自動ログインというのはブラウザを閉じても有効なんですか?
これはブラウザを閉じても有効と言うことになります。

お教えいただいた情報と、自分で調べた情報を参考に
初回ログイン時にランダム文字列のキーを作成し、それをDBに格納、
それをクッキーにも持たせて認証という方法で制作しました。
そのキーはブラウザを閉じてからの自動ログイン時に
再度書き換えられるように設定しました。
これでかなりパフォーマンスは上がったと思っています。

また問題になっていたセッションの問題ですが、

$tmp = $_SESSION[login];
session_destroy();
$_SESSION[login] = $tmp;

上記の方法で問題なく対応できています。

色々とご丁寧にありがとうございました。
奥の深い部分でこれがゴールと言うものはないと思いますが、
日々精進を続けてまいります。

お礼日時:2011/11/03 20:10

>盗聴+クッキーの改変で容易に突破されそう



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

ご回答ありがとうございます。
当初はセッションによる管理を考えていましたが、
私のセッションに関する知識が乏しいため、
下記のような問題により、
ログイン認証ではセッションを使用していません。

ログインチェックで
例えば$_SESSION['login']に
ログインチェック関係の変数を入れるとします。

これを使用したプログラムを全てのページに埋め込めば
確かにログインチェックができるかと思います。

ところがログイン後のページの各所で
登録フォームや送信フォームが多数あり、
その中で多数のセッション変数を使用しています。

それらのフォームの送信完了後に、
そのフォームで使用したセッション変数のみをクリアしたいのですが、
session_unsetやsession_destroyなどを使用すると、
ログインチェック用のセッション変数までクリアしてしまうため、
この辺りがうまくいかずにログイン認証にはセッションを使用していませんでした。

本題の質問とは外れてしまいますが、
ログインチェック用のセッションとその他のフォーム用のセッションに
分けて使用する方法はありませんでしょうか?

それともフォーム送信後に
いちいち使用したセッション変数のみを
一つずつunset($_SESSION['hoge']);する必要があるのでしょうか?

もしそのようなことに関する情報がありましたら
お教え願えれば光栄です。

ちなみに、ID/PWはcryptで暗号化して、
DBに格納されており、ログイン時のみ比較を行っています。

お礼日時:2011/11/02 22:08

このQ&Aに関連する人気のQ&A

このQ&Aと関連する良く見られている質問

QPHP cryptでパスワードを暗号化

お世話になります。

現在、会員登録フォームを作成しており入力されたパスワードをcryptで暗号化しDBに登録させる処理をコーディング中です。

以下の文で暗号化を行おうと試みたのですが、DB内では文字制限が16文字以内となっているため、暗
号化した長い文字列では登録が不可能です。
$setpasswordは入力されたパスワードの文字列が格納されます。
---
$encrypted_password = crypt($setpassword);
---
DBを弄ることができませんので、どうにか暗号化文字列を16文字以内に抑える方法がないものかと思っております。

お力添えよろしくお願い致します。

Aベストアンサー

その文字列制限というのがどのような仕様なのかわからないのでなんともいえませんが
考え方は3つ

・パスワードなんて所詮非可逆なものなので復号化する必要はないので
先頭の16文字だけ保存しておいて合致させればある程度パスワードの用をなします
ただし全く別のパスワード入力がたまたま同じになる可能性はあります

・暗号化されたデータを複数のカラムに振り分ける

・そもそも暗号化しない(セキュリティ的にはありえない)

Qphpの/の無い可逆暗号化出来る関数はありませんか

/の無い可逆暗号化出来る関数はありませんか

Aベストアンサー

「/の無い」の意味するところがわかりませんが,
McryptやOpenSSLの関数群を使えば,暗号を利用することができます。

refs)
http://php.net/manual/ja/book.mcrypt.php
http://php.net/manual/ja/book.openssl.php

Mcryptを使う場合にmcrypt_list_algorithmsの出力を見ると,現在の標準的な共通鍵暗号方式であるAESが無かったりしますが,
AES以前からの名前であるrijndaelで登録されているためで,実質的にAESを利用することができます。
なお,公開鍵暗号方式を利用する場合は,OpenSSLの関数群を利用することになります……色々面倒ですが。

Q会員サイトのユーザーIDについて

現在、phpで会員サイトを作る勉強をしています。

最近、よくメールアドレスとパスワードを使用して
会員専用ページにログインさせているサイトを目にします。

確かに、各サイト毎に登録するようなユーザーIDは忘れやすいので、メールアドレスとパスワードの組み合わせでログインしてもらう方がユーザー側からしても良いと思いますが、

実際、メールアドレスでログイン認証している会員サイトでもユーザー側にはわからない管理用のユーザーIDというのは付与しているのでしょうか?

付与している場合、それぞれのユーザーIDが同じにならないように乱数で作成するパターンが多いのでしょうか?

ユーザーIDの法則についてはサイト毎に異なるかとは思いますが、
実際、ほとんどのサイトはどのような決まりで付与しているのか気になり、質問しました。

ご回答、よろしくお願いします。

Aベストアンサー

「内部的に」持っているでしょうね。システムによっては「メールアドレスの変更」も可能にしたいということはあるでしょうから。

それこそ新規登録でデータベースのユーザテーブルにレコードを追加した時点で、auto_increment(シノニム)で付番された値でかまわないでしょう(重複しないことがデータベース側で保証されている)。システム内で見分けられればいいだけなので。わざわざ乱数を使うこともありません。

QReceived-SPFでレンタルサーバーのIDが

 最近、PHPの勉強を始めた者です。
 初心者本を読みながら、ようやくメールを送信するところまで来ました。

 mail関数やmb_send_mail関数を使って送るというのは分かったんですが、この方法を送ったメールのヘッダにちょっと問題が・・・。

 ロリポップサーバーにムームードメインの組み合わせて使っているんですが、Yahoo!のメールアドレスに送ったメールのヘッダに


Received-SPF:none (users094.phy.lolipop.jp: domain of ◯◯◯◯@users094.phy.lolipop.jp does not designate permitted sender hosts)


というものがついてしまいます。

 別にロリポップサーバーを使ってることが知られても構わないんですが、◯◯◯◯の部分が問題でして、ロリポップ内のFTP・WebDAVで使われてるアカウントが入ってくるんです。

 これがロリポップにログインするためのアカウントを少し入れ替えただけで、使ったことある人ならモロバレの状態。

 まあ、パスワードが分からなければログインは出来ないんですが、なんだか気持ち悪いんですよね(^_^;

 調べてみるとSPFというのはメールの認証か何かだそうですが、ネットで検索しつつ、ムームードメインのDNSにして、カスタムDNSでSPFの設定をしてみても、上記のヘッダはnoneのままでついてきます。

 これを何とか消す方法はないもんでしょうか?

 最近、PHPの勉強を始めた者です。
 初心者本を読みながら、ようやくメールを送信するところまで来ました。

 mail関数やmb_send_mail関数を使って送るというのは分かったんですが、この方法を送ったメールのヘッダにちょっと問題が・・・。

 ロリポップサーバーにムームードメインの組み合わせて使っているんですが、Yahoo!のメールアドレスに送ったメールのヘッダに


Received-SPF:none (users094.phy.lolipop.jp: domain of ◯◯◯◯@users094.phy.lolipop.jp does not designate permitted sender hosts)


...続きを読む

Aベストアンサー

「mail関数やmb_send_mail関数を使って送る」ときに、第5引数はどうなっていますか?

第4引数でメールヘッダのFromを指定しないとき同様、第5引数でエンベロープのmailfromを指定しなければmailfromは「デフォルトのアカウント」になってしまいます(そのアカウントでSPFがチェックされる)。

なので

mb_send_mail($to, $subject, $message, 'From: info@example.com' , '-f info@example.com');

のように、第5引数の -f オプションでも当該サーバで運用しているドメインのメールアドレスをキチンと指定すれば、そのメールアカウントのドメインで生成されるハズです。

#というか、今数パターン試して確認しました(汗

Qmysqlのinsert_idを再利用したい。

オブジェクト指向型で
$new_id = $mysqli->insert_id;
としているのですが、実際に挿入されるレコードのIDは正しいのですが、
$new_idにはゼロが返されてしまいます。

insert_idで取得したIDを変数へ代入することは可能なのでしょうか?
検索しても見つからずここに頼る事にしました・・

ちなみに、$new_idに正しいIDがはるのであれば、
ID番号.jpgやID番号.pdfのようにファイル名に利用しようと考えています。

Aベストアンサー

>このデータ投入の前に自動生成のIDを取得したい

なるほど、それは質問内容から読み取れない
どうしてもやりたいなら、当該テーブルのidフィールドに対して
max(idフィールド)+1すればよいでしょう。
ただしその運用方法だとタイミングによってはデータ競合の可能性もでてくるので
インサートするときにはauto_incrementを期待せず、
idを明示してデータ投入する必要があります。
つまりはauto_increment機能は使わない方がよいということ。

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード


人気Q&Aランキング

おすすめ情報