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

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

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

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

Q&A

解決済

3回答

680閲覧

ログイン認証ページでのセキュリティ

suke1001

総合スコア7

PHP

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

0グッド

1クリップ

投稿2021/07/30 21:47

編集2021/07/30 21:58

会員登録のページを作成しましたが、セキュリティの部分で書き直したい箇所があります。

データベースにパスワードを登録する際にセキュリティの面で [sha1]はマニュアルでは推奨されていないので[password_hash]を使ってパスワードをハッシュ化することができました。(chech.php)

ですが、ログインの認証時に[password_verify]でハッシュ化されたパスワードの第二引数(login.php)をどのように書けばいいのかわかりません。

PHPの教材を購入してこのコードを書いてみましたので、コードが汚く読みにくいかもしれませんがもしよろしければ教えていただきたいです。

よろしくお願いします。

loginphp

1<?php 2require('../dbconnect.php'); 3session_start(); 4error_reporting(E_ALL ^ E_NOTICE); 5 6if ($_COOKIE['email'] != '') { 7 $_POST['email'] = $_COOKIE['email']; 8 $_POST['password'] = $_COOKIE['password']; 9 $_POST['save'] = 'on'; 10} 11 12if (!empty($_POST)) { 13 if ($_POST['email'] != '' && $_POST['password'] != '') { 14 $login = $db->prepare('SELECT * FROM members WHERE email=? AND password=?'); 15 $login->execute(array( 16 $_POST['email'], 17 password_verify($_POST['passowrd'], ) 18 )); 19 $member = $login->fetch(); 20 password_verify($_POST['password'], $member['password']); 21 22 if ($member) { 23 $_SESSION['id'] = $member['id']; 24 $_SESSION['time'] = time(); 25 26 if ($_POST['save'] == 'on') { 27 setcookie('email', $_POST['email'], time()+60*60*24*14); 28 setcookie('password', $_POST['password'], time()+60*60*24*14); 29 } 30 31 header('Location:index.php');exit(); 32 } else { 33 $error['login'] = 'failed'; 34 } 35 } else { 36 $error['login'] = 'blank'; 37 } 38} 39 40?> 41 42<div class="lead"> 43 <p>メールアドレスとパスワードを記入してログインしてください</p> 44 <p>入会手続きがまだな方はコチラからどうぞ</p> 45 <p>&raquo;<a href="../join/index.php">入会手続きをする</a></p> 46</div> 47<form action="" method="post"> 48 <dl> 49 <dt>メールアドレス</dt> 50 <dd> 51 <input type="text" name="email" size="35" maxlength="255" value="<?php echo h($_POST['email']); ?>"> 52 <?php if ($error['login'] == 'blank'): ?> 53 <p class="error">※メールアドレスとパスワードを入力して下さい</p> 54 <?php endif; ?> 55 <?php if ($error['login'] == 'failed'): ?> 56 <p class="error">※ログインに失敗しました。正しくご入力ください。</p> 57 <?php endif; ?> 58 </dd> 59 <dt>パスワード</dt> 60 <dd> 61 <input type="password" name="password" size="35" maxlength="255" value="<?php echo h($_POST['password']); ?>"> 62 </dd> 63 <dt>ログイン情報の記録</dt> 64 <dd> 65 <input id="save" type="checkbox" name="save" value="on"><label for="save">次回からは自動的にログインする</label> 66 </dd> 67 </dl> 68 <div><input type="submit" value="ログインする"></div> 69</form>

checkphp

1<?php 2session_start(); 3require('../dbconnect.php'); 4 5if (!isset($_SESSION['join'])) { 6 header('Location: index.php'); 7 exit(); 8} 9 10if (!empty($_POST)) { 11 $stmt = $db->prepare('INSERT INTO members SET name=?, email=?, password=?, picture=?, created=NOW()'); 12 echo $ret = $stmt->execute(array( 13 $_SESSION['join']['name'], 14 $_SESSION['join']['email'], 15 password_hash($_SESSION['join']['password'],PASSWORD_DEFAULT), 16 $_SESSION['join']['image'] 17 )); 18 unset($_SESSION['join']); 19 20 header('Location: thanks.php'); 21 exit(); 22} 23?> 24 25<form action="" method="post"> 26 <input type="hidden" name="action" value="submit"> 27 <dl> 28 <dt>ニックネーム</dt> 29 <dd> 30 <?php echo h($_SESSION['join']['name']); ?> 31 </dd> 32 <dt>メールアドレス</dt> 33 <dd> 34 <?php echo h($_SESSION['join']['email']); ?> 35 </dd> 36 <dt>パスワード</dt> 37 <dd> 38 【表示されません】 39 </dd> 40 <dt>写真など</dt> 41 <dd> 42 <img src="../post/member_picture/<?php echo h($_SESSION['join']['image']); ?>" width="300" height="300" alt=""> 43 </dd> 44 </dl> 45 <div><a href="index.php?action=rewrite">&laquo;&nbsp; 書き直す</a> | 46 <input type="submit" value="登録する"></div> 47</form>

dbconnectphp

1<?php 2try { 3 $db = new PDO ('mysql:dbname=mini_bbs;host=localhost;charset=utf8', 'root', 'root'); 4} catch (PDOException $e) { 5 echo 'DB接続エラー: ' . $e->getMessage(); 6} 7 8function h($value) { 9 return htmlspecialchars($value, ENT_QUOTES); 10} 11 12function makeLink($value) { 13 return mb_ereg_replace("(https?)(://[[:alnum:]+$\;?.%,!#~*/:@&=_-]+)",'<a href="\1\2">\1\2</a>', $value); 14} 15 16?> 17

indexphp

1<?php 2require('../dbconnect.php'); 3 4session_start(); 5error_reporting(E_ALL ^ E_NOTICE); 6 7if (!empty($_POST)) { 8 if ($_POST['name'] == '') { 9 $error['name'] = 'blank'; 10 } 11 if ($_POST['email'] == '') { 12 $error['email'] = 'blank'; 13 } 14 if (strlen($_POST['password']) < 4) { 15 $error['password'] = 'length'; 16 } 17 if ($_POST['password'] == '') { 18 $error['password'] = 'blank'; 19 } 20 21 $fileName = $_FILES['image']['name']; 22 if (!empty($fileName)) { 23 $ext = substr($fileName, -3); 24 if ($ext != 'jpg' && $ext != 'gif') { 25 $error['image'] = 'type'; 26 } 27 } 28 29 if (empty($error)) { 30 $member = $db->prepare('SELECT COUNT(*) AS cnt FROM members WHERE email=?'); 31 $member->execute(array($_POST['email'])); 32 $record = $member->fetch(); 33 if ($record['cnt'] > 0) { 34 $error['email'] = 'duplicate'; 35 } 36 } 37 38 if (empty($error)) { 39 $image = date('YmdHis') . $_FILES['image']['name']; 40 move_uploaded_file($_FILES['image']['tmp_name'], '../post/member_picture/' . $image); 41 42 $_SESSION['join'] = $_POST; 43 $_SESSION['join']['image'] = $image; 44 header('Location: check.php'); 45 exit(); 46 } 47 48 if ($_REQUSET['action'] == 'rewrite') { 49 $_POST = $_SESSION['join']; 50 $error['rewite'] = true; 51 } 52} 53 54?> 55 56 57<p>次のフォームに必要事項を記入してください。</p> 58<form action="" method="post" enctype="multipart/form-data"> 59 <dl> 60 <dt>ニックネーム<span class="required">必須</span></dt> 61 <dd><input type="text" name="name" size="35" maxlength="255" value="<?php echo h($_POST['name']); ?>"> 62 <?php if ($error['name'] == 'blank'): ?> 63 <p class="error">※ニックネームを入力してください</p> 64 <?php endif; ?> 65 </dd> 66 67 <dt>メールアドレス<span class="required">必須</span></dt> 68 <dd><input type="text" name="email" size="35" maxlength="255" value="<?php echo h($_POST['email']); ?>"> 69 <?php if ($error['email'] == 'blank'): ?> 70 <p class="error">※メールアドレスを入力してください</p> 71 <?php endif; ?> 72 <?php if ($error['email'] == 'duplicate'): ?> 73 <p class="error">※指定したメールアドレスは既に登録されています</p> 74 <?php endif; ?> 75 </dd> 76 77 <dt>パスワード<span class="required">必須</span></dt> 78 <dd><input type="password" name="password" size="10" maxlength="20"> 79 <?php if ($error['password'] == 'blank'): ?> 80 <p class="error">※パスワードを入力してください</p> 81 <?php endif; ?> 82 <?php if ($error['password'] == 'length'): ?> 83 <p class="error">※パスワードは4文字以上で入力してください</p> 84 <?php endif; ?> 85 </dd> 86 87 <dt>写真など</dt> 88 <dd><input type="file" name="image" size="35"/> 89 <?php if ($error['image'] == 'type'): ?> 90 <p class="error">※写真などは[.gif]または[.jpg]の画像を指定してください</p> 91 <?php endif; ?> 92 <?php if (!empty($error)): ?> 93 <p class="error">恐れ入りますが、画像を改めて指定してください</p> 94 <?php endif; ?> 95 </dd> 96 </dl> 97 <div><input type="submit" value="入力内容を確認する"></div> 98</form>

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

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

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

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

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

guest

回答3

0

ベストアンサー

PHPマニュアル確認しましょう。

password_verify()

パスワードがハッシュにマッチするかどうかを調べる
指定したハッシュがパスワードにマッチするかどうかを調べます。
password_hash() は、 アルゴリズムやコスト、ソルトといった情報もハッシュに含めて返すことに注意しましょう。 したがって、ハッシュの検証に必要な情報はすべてそこに含まれていることになります。 これで、検証関数がハッシュの検証をするときに、ソルトやアルゴリズム情報を別の場所から取得する必要がなくなります。
password_verify(string $password, string $hash): bool
password
ユーザーのパスワード。
hash
password_hash() が作ったハッシュ。

つまり、SELECTと同時にどうにかするものではなく、SELECTして取得されたhash済み文字列と入力値を比較することになります。

一般的にユーザIDは一意であるものなので、ユーザIDだけでSELECTするので十分です。

投稿2021/07/30 22:59

編集2021/07/30 23:00
m.ts10806

総合スコア80765

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

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

suke1001

2021/07/30 23:11

ご回答ありがとうございます。 マニュアルをしっかり読んだつもりでいたのですが、理解を深めることができませんでした。 パスワードまでSELECTで取得せずにSELECTされたユーザーIDとパスワードが一致するかを調べるということでしょうか?僕のこの解釈があっているか教えていただけたら幸いです。
m.ts10806

2021/07/30 23:14

機能確認をしっかりしてから使いましょう、という意味ですね。 その機能が求める引数、役割、何を返すか が書いてありますしその3点が理解できれば十分です。サンプルコードもあるので確認してください。 >パスワードまでSELECTで取得せずに は合っています。 >SELECTされたユーザーIDとパスワードが一致するかを調べるということでしょうか? は違います。 正しくは「IDなど一意となる主キーのみでSELECTし、結果で得られたパスワードと入力値が一致するかPHPの機能で検査する」です。
suke1001

2021/07/30 23:18

すごくわかりやすい表現で言葉の意味を理解することができました。 先程の、コードはパスワードをデタラメにしてもログインできてしまいました。 なので、返却値について調べてもう一度、チャレンジしてみます。
suke1001

2021/07/31 00:55

結構、時間がかかってしまいましたがうまく動作するようになりました。password_verifyは返却値もセットでコードを書くことが学べました。 お手助け色々とありがとうございました。
guest

0

ご指摘いただいた通りにif文にてtrue/falseの判定を追加したところうまく動作しました。
ログインもパスワードでしかログインされないようになりました。

checkphp

1<?php 2require('../dbconnect.php'); 3session_start(); 4error_reporting(E_ALL ^ E_NOTICE); 5 6if ($_COOKIE['email'] != '') { 7 $_POST['email'] = $_COOKIE['email']; 8 $_POST['password'] = $_COOKIE['password']; 9 $_POST['save'] = 'on'; 10} 11 12if (!empty($_POST)) { 13 if ($_POST['email'] != '' && $_POST['password'] != '') { 14 $stmt = $db->prepare('SELECT * FROM members WHERE email = :email'); 15 $stmt->execute(array(':email' => $_POST['email'])); 16 $member = $stmt->fetch(PDO::FETCH_ASSOC); 17 18 if( password_verify($_POST['password'], $member['password'])) { 19 $_SESSION['id'] = $member['id']; 20 $_SESSION['time'] = time(); 21 header('Location:index.php');exit(); 22 } else { 23 $error['login'] = 'failed'; 24 } 25 } else { 26 $error['login'] = 'blank'; 27 } 28 29 if ($_POST['save'] == 'on') { 30 setcookie('email', $_POST['email'], time()+60*60*24*14); 31 setcookie('password', $_POST['password'], time()+60*60*24*14); 32 } 33 } 34 35?> 36 37<div class="lead"> 38 <p>メールアドレスとパスワードを記入してログインしてください</p> 39 <p>入会手続きがまだな方はコチラからどうぞ</p> 40 <p>&raquo;<a href="../join/index.php">入会手続きをする</a></p> 41</div> 42<form action="" method="post"> 43 <dl> 44 <dt>メールアドレス</dt> 45 <dd> 46 <input type="text" name="email" size="35" maxlength="255" value="<?php echo h($_POST['email']); ?>"> 47 <?php if ($error['login'] == 'blank'): ?> 48 <p class="error">※メールアドレスとパスワードを入力して下さい</p> 49 <?php endif; ?> 50 <?php if ($error['login'] == 'failed'): ?> 51 <p class="error">※ログインに失敗しました。正しくご入力ください。</p> 52 <?php endif; ?> 53 </dd> 54 <dt>パスワード</dt> 55 <dd> 56 <input type="password" name="password" size="35" maxlength="255" value="<?php echo h($_POST['password']); ?>"> 57 </dd> 58 <dt>ログイン情報の記録</dt> 59 <dd> 60 <input id="save" type="checkbox" name="save" value="on"><label for="save">次回からは自動的にログインする</label> 61 </dd> 62 </dl> 63 <div><input type="submit" value="ログインする"></div> 64</form>

投稿2021/07/31 00:53

suke1001

総合スコア7

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

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

m.ts10806

2021/07/31 01:38

回答も編集できるので投稿し直す必要はありません。片方削除依頼をだし、まとめてください。
suke1001

2021/07/31 01:50

了解しました!ありがとうございます。
guest

0

このようにコードを書き換えたところ上手く動作しました。

checkphp

1<?php 2require('../dbconnect.php'); 3session_start(); 4error_reporting(E_ALL ^ E_NOTICE); 5 6if ($_COOKIE['email'] != '') { 7 $_POST['email'] = $_COOKIE['email']; 8 $_POST['password'] = $_COOKIE['password']; 9 $_POST['save'] = 'on'; 10} 11 12if (!empty($_POST)) { 13 if ($_POST['email'] != '' && $_POST['password'] != '') { 14 $stmt = $db->prepare('SELECT * FROM members WHERE email = :email'); 15 $stmt->execute(array(':email' => $_POST['email'])); 16 $member = $stmt->fetch(PDO::FETCH_ASSOC); 17 password_verify($_POST['password'], $member['password']); 18 19 if ($member) { 20 $_SESSION['id'] = $member['id']; 21 $_SESSION['time'] = time(); 22 23 if ($_POST['save'] == 'on') { 24 setcookie('email', $_POST['email'], time()+60*60*24*14); 25 setcookie('password', $_POST['password'], time()+60*60*24*14); 26 } 27 28 header('Location:index.php');exit(); 29 } else { 30 $error['login'] = 'failed'; 31 } 32 } else { 33 $error['login'] = 'blank'; 34 } 35} 36 37?> 38 39<div class="lead"> 40 <p>メールアドレスとパスワードを記入してログインしてください</p> 41 <p>入会手続きがまだな方はコチラからどうぞ</p> 42 <p>&raquo;<a href="../join/index.php">入会手続きをする</a></p> 43</div> 44<form action="" method="post"> 45 <dl> 46 <dt>メールアドレス</dt> 47 <dd> 48 <input type="text" name="email" size="35" maxlength="255" value="<?php echo h($_POST['email']); ?>"> 49 <?php if ($error['login'] == 'blank'): ?> 50 <p class="error">※メールアドレスとパスワードを入力して下さい</p> 51 <?php endif; ?> 52 <?php if ($error['login'] == 'failed'): ?> 53 <p class="error">※ログインに失敗しました。正しくご入力ください。</p> 54 <?php endif; ?> 55 </dd> 56 <dt>パスワード</dt> 57 <dd> 58 <input type="password" name="password" size="35" maxlength="255" value="<?php echo h($_POST['password']); ?>"> 59 </dd> 60 <dt>ログイン情報の記録</dt> 61 <dd> 62 <input id="save" type="checkbox" name="save" value="on"><label for="save">次回からは自動的にログインする</label> 63 </dd> 64 </dl> 65 <div><input type="submit" value="ログインする"></div> 66</form>

投稿2021/07/30 23:07

suke1001

総合スコア7

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

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

m.ts10806

2021/07/30 23:09

password_verify()の返却値をチェックしていないのでemailが合っていればパスワード間違っていても通ります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問