質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

3回答

1434閲覧

【PHP】【トークン認証】初回時(認証の2度目からは成功)に認証失敗になる問題の解決方法【初心者】

shimane

総合スコア98

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2017/12/16 10:42

現在プログラムの勉強をしている者です。

現在、お問い合わせフォームの作成を行っていまして
送信時に「トークン認証」を行って、不正な投稿ではないかのチェックを行っているのですが
自力で解決できない問題が発生してしまいました。

【現象】

html側に仕込んでいるトークンと
PHP側のトークンを検証して、一致していたら処理を実行、不一致ならエラーが表示というものを
ドットインストールさんや書籍・ネットで調べて試してみたのですが

初回時に限り「トークンの認証失敗」が必ず起きてしまいます。

原因を探る為にhtml側を見てみた所、
初回時に限って

html

1<input type="hidden" name="token" value="<br /> 2<b>Notice</b>: Undefined index: token in <b>

このようにトークンがありませんという風に表示されていました。

エラーで失敗になった2回目からは

html

1 <input type="hidden" name="token" value="a05a840362109ee44b661e97326447ae"> 2 <input type="submit" value="送信" class="btn btn-primary"> 3

このように表示されていまして
トークンの認証もきちんと問題なく出来ていました。

そこで、最初からhtml側にトークンを表示させていればトークンの認証失敗が起きないのでは?と考えて
色々試してみたのですが上手くいきませんでした。

下記が書いたコードです。

//PHP // postなら処理を実行する if($_SERVER['REQUEST_METHOD']==='POST'){ if (!isset($_SESSION['token'])) { $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16)); } if ( !isset($_SESSION['token']) || !isset($_POST['token']) || $_SESSION['token'] !== $_POST['token'] ) { throw new \Exception('トークンの認証に失敗しています。もう1度、お問い合わせのメッセージの送信を試してみてください。'); } else { //トークン認証成功時に行う処理です。 $otoiawasename = h($_POST['toiawase_name']); $otoiawaseemail = h($_POST['toiawase_email']); $otoiawasebody = h($_POST['toiawase_body']); $sql = "insert into otoiawase (name, mail, otoiawase, created) values (:name,:mail,:otoiawase,now()) ON DUPLICATE KEY UPDATE created = now() "; $stmt = $db->prepare($sql); $stmt->execute([ ':name' => $otoiawasename, ':mail' => $otoiawaseemail, ':otoiawase' => $otoiawasebody ]); } header('Location:http://test.com/abut2.php'); } //HTML <form class="form-horizontal" action="" method="post" style="margin-bottom:15px;"> <div class="form-group"> <label class="control-label" for="email">お名前</label> <input type="text" name="toiawase_name" class="form-control" placeholder="お名前"> </div> <div class="form-group"> <label class="control-label" for="email">Email</label> <input type="email" name="toiawase_email" class="form-control" required placeholder="Email"> </div> <div class="form-group"> <label class="control-label" for="email">内容</label> <textarea name="toiawase_body" class="form-control" maxlength="1000" minlength="5" required cols=40 rows=10></textarea> </div> <div class="form-group"> <input type="hidden" name="token" value="<?php echo h($_SESSION['token']); ?>"> <input type="submit" value="送信" class="btn btn-primary"> </div> </form>

安易に初めから

$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16));

こちらを「POST時の条件判定」よりも前に書いて
最初から$_SESSION['token']に入れてみた所、
htmlのソースには初回時からトークンが表示されましたが、
今度はPOST時のトークン認証で不一致となりエラーが表示されてしまいました。

実行結果:

echo $_SESSION['token']; 結果: cb9b04d3cc2549b8b5207d8fed231468 echo $_POST['token']; 結果: aa70c6aced1c45390e625a3df47a2a9c 不一致となってしまいまいsた。

解決方法をご存知の方や
コードの間違いに気づかれた方がいらっしゃいましたら
お力をお貸し頂けると、とても嬉しいです。

どうかよろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

if($_SERVER['REQUEST_METHOD']==='POST')でない場合に、$_SESSION['token']が空のままになるのが問題です。

他に、コードの考え方に問題があるので、以下を参考に修正すると良いです。
$_GET, $_POSTなどを受け取る際の処理
「何故htmlspecialcharsを通すのか?」を一言でどうぞ

投稿2017/12/16 10:53

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/12/16 10:54

あ、おそかったw
shimane

2017/12/16 11:13

回答有難うございます! 私はまだまだ初心者の中でも下っ端なので >if($_SERVER['REQUEST_METHOD']==='POST')でない場合に、$_SESSION['token']が空のままになるのが問題です。 この発言をしてくださってようやく正解にたどり着く事が出来ました! //初回時・POSTを行う前の段階で認証用のトークンを設定しておきます。 if($_SERVER['REQUEST_METHOD'] !=='POST'){ $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16)); } PHPにてこのコードを追加することで 初回時にも認証エラーが表示されることなく正常に処理を行う事が出来ました。 有難うございます! 教えてくださった $_GET, $_POSTなどを受け取る際の処理 「何故htmlspecialcharsを通すのか?」を一言でどうぞ にも目を通して勉強を進めていきたいと思います! まだまだプログラムの勉強を開始したばかりで頭が混乱する事が多いですが 一生懸命頑張っていこうと思います。 回答してくださって有難うございます。本当に助かりました! 大感謝です!
guest

0

トークンのセットはGETメソッドの時に必要なのに、POSTメソッドの場合のみ処理されているので、初回は未定義になるようですね。

投稿2017/12/16 10:50

ockeghem

総合スコア11701

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shimane

2017/12/16 11:09

回答有難うございます! お恥ずかしながら勉強中の身で、GETメソッドの時の処理をどうすれば・・・と考える力がまだ足りなく せっかくの助言を頂きながら、私の実力不足で回答までたどり着けず申し訳ありません。 今回は別の方にベストアンサーとなりましたが とっても勉強になりました。大感謝です!
guest

0

php

1 <input type="hidden" name="token" value="<?php echo h($_SESSION['token']); ?>">

php

1 <input type="hidden" name="token" value="<?php if (isset($_SESSION['token'])) {echo h($_SESSION['token']);} ?>">

投稿2017/12/16 10:46

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shimane

2017/12/16 11:06

回答有難うございます! 実際に試してみた所、 初回時にはvalue=の所が空白となっていまして POST時にエラーが発生しました。 ですが、2度目からはトークンの認証が成功していました! 先ほどの回答でもそうなのですが、 勉強になる事が多く、とても感謝しています。有難うございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問