初めて投稿させて頂きます。
初心者なので、初歩的な質問で申し訳ございません。
ユーザーが氏名を最大50個まで入力し、確認ボタンを押すと、内容確認画面(入力値一覧)に遷移する処理を書いています。
会員式のシステムなので、今までログインいていることのみをチェックしておりましたが、
今回初めてCRSF対策でトークンを発行して、チェックが必要なページに対して入れています。
そこで今回迷っているのが、氏名が既に登録されているかどうかのチェックをDBに対して行うのですが、現状以下の様な流れとなっています。
1.氏名を入力
2.「確認」ボタンを押下(自分に対して、トークンとhidden値「check」をPOST)
3.if (isset($_POST['check']) { でifの中に入り、その中でDB既存チェック
4.エラーならdie('エラー');
5.OKなら確認画面へリダイレクト
といった感じです。
この時、リダイレクト先へトークンを渡せない為に、確認画面に対して氏名をPOSTされると外部から氏名を登録されてしまいます。
やはりこの場合は、確認画面でチェックして、エラーだと「エラーメッセージ+入力画面に戻る」のみ表示させるべきなのでしょうか?
別画面に遷移⇒戻る よりも、そのページ内でチェックして弾いてあげるほうが使いやすいかと思い悩んでおります。
説明が下手ですみません。
以下はソースです。
PHP
1【input.php】 2<?php 3 // セッション開始 4 session_start(); 5 6 <!-- チェッククラスの読み込み --> 7 include_once('check.php'); 8 9 // ログイン状態チェック + CSRF対策 10 if ( ( !isset($_SESSION["NAME"]) ) || 11 ( !CsrfValidator::funcTokenValidate(filter_input(INPUT_POST, 'token'))) ) { ←トークンのチェックです 12 // ログイン画面へリダイレクト 13 header("Location: login.php"); 14 } 15 16 if ( isset($_POST['check']) ) { 17 チェックフラグがセットされている場合 18 19 $UserName = 入力された氏名を配列として格納(); 20 21 //------------------ 22 // 氏名既存チェック 23 //------------------ 24 $pdo = new PDO(DSN, ユーザー名, パスワード, array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION)); 25 26 $stmt = $pdo->prepare("SELECT NAME FROM 氏名テーブル WHERE NAME = ?"); 27 foreach ( $UserName as $name ) { 28 $stmt->execute(array($name)); 29 30 //チェック 31 if ( $row = $stmt->fetch(PDO::FETCH_ASSOC) ) { 32 // 既に登録された氏名の場合 33 die("{$row['NAME']}は既に登録されています。"); 34 } 35 } 36 37 // 確認フォームへ 38 header("Location: confirm.php"); // この時、トークンを渡せない 39 } 40 ?> 41 42<!doctype html> 43<html> 44<head> 45<meta charset="utf-8"> 46<title>入力画面</title> 47</head> 48 49<body> 50 <!---------------- 51 入力フォーム 52 -----------------> 53 <div class="form_wrapper cont"> 54 <form action="menber_add_conf.php" method="post" name="frmAdd" onSubmit="return 入力チェック()"> 55 <table class="formTable_v"> 56 <tbody> 57 <tr> 58 <th> 59 氏名 60 </th> 61 </tr> 62 <!-- この下に入力領域を50個用意 --> 63 ・・・ 64 ・・・ 65 ・・・ 66 ・・・ 67 </tbody> 68 </table> 69 <!-- トークンのセット --> 70 <?=CsrfValidator::funcSetToken()?> <!-- このセットが、リダイレクトではできないですよね・・? --> 71 <!-- チェックフラグのセット --> 72 <input type="hidden" name="check" value="check"> 73 74 <button type="submit" id="submit">確認画面へ</button> 75 </form> 76 </div> 77</body> 78</html> 79
一応連携しておきますが、トークンチェックに関するクラスは以下の通りです。
php
1【check.php】 2 class CsrfValidator { 3 4 // ハッシュ用のアルゴリズムをセット(SHA256) 5 const HASH_ALGO = 'sha256'; 6 7 //======================================= 8 // トークン生成処理 9 //======================================= 10 private static function Generate() 11 { 12 if (session_status() === PHP_SESSION_NONE) { 13 throw new \BadMethodCallException('Session is not active.'); 14 } 15 return hash(self::HASH_ALGO, session_id()); 16 } 17 18 //======================================= 19 // トークンチェック処理 20 //======================================= 21 public static function Validate($token, $throw = false) 22 { 23 $success = self::funcTokenGenerate() === $token; 24 if (!$success && $throw) { 25 throw new \RuntimeException('CSRF validation failed.', 400); 26 } 27 return $success; 28 } 29 30 //======================================= 31 // トークンセット処理 32 //======================================= 33 public static function SetToken() { 34 return '<input type="hidden" name="token" value="' . self::funcTokenGenerate() . '">'; 35 } 36 }
わかりにくくて申し訳ございませんが、ご指摘の程宜しくお願いいたします。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/01/09 02:49
2018/01/24 00:01