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

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

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

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

Q&A

1回答

598閲覧

header関数によってa.phpからb.phpに遷移したとき、a.phpから遷移したことを保証する手段とは・・・?

y_programming

総合スコア48

PHP

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

0グッド

2クリップ

投稿2022/10/05 12:14

編集2022/10/09 03:12

実現したいこと

「b.php」を実行するときに、「a.php」から遷移してきた場合のみ実行する、という実装を安全につくりたいのです。

セッションをつかう作戦はどうでしょうか

リファラをつかうやりかたは安定しないようでしたので、セッションをつかうやりかたはどうだろうと思いました。

a.php

1<?php 2 session_start(); 3 $_SESSION['a'] = 'a'; 4 header("Location: ./b.php");

↑こちらのa.phpから↓のb.phpへリダイレクトします!

b.php

1<?php 2 session_start(); 3 if($_SESSION['a'] !== 'a'){ 4 exit; 5 } 6 echo "a.phpから遷移してきたb.phpです。";

b.phpが実行されたときに、「$_SESSION['a']に"a"という文字列が入っていない…これは、a.php以外から遷移してきたに違いない!」と判断し、スクリプトを終了します。
セッションのキーと値を便宜上"a"としておりますが、このキーや値を複雑なものにするといいのかな、と考えました。
しかし…もっと安全なやりかたが存在するのならばそれを知りたい!と考え質問を投稿させていただきました。
「想定しているページからの遷移しか許可しない」という実装をする上で何が必要なのか。
アドバイス等いただけますと幸いです。よろしくお願いいたします!

2022-10-09 お昼 追記

ログイン画面(login.php)でユーザ名とパスワードを入力

a.phpへ遷移し、DBからデータを取得し、セッション変数に入れてb.phpで扱えるようにする

b.phpへ遷移し、取得したデータを表示

という一連の流れを実装しようとしました。3つのファイルのソースは下記のものです!

login.php

a.php

1<?php 2 session_start(); 3 if(array_key_exists("csrf_token", $_SESSION)){ 4 if($_SESSION['csrf_token'] !== $_POST['csrf_token']){ 5 //トークンが一致しないためlogin.php以外から遷移してきたものと断定し、ログイン画面へ強制遷移 6 header("Location: ./login.php"); 7 exit; 8 } 9 }else{ 10 //セッション変数にCSRFトークンが入っていなかった時点で不正リクエストと断定し、ログイン画面へ強制遷移 11 header("Location: ./login.php"); 12 exit; 13 } 14 15 define("USER", "user"); 16 define("PASSWORD", "pass"); 17 18 if(isset($_POST['username']) && isset($_POST['password'])){ 19 if($_POST['username'] !== USER || $_POST['password'] !== PASSWORD){ 20 echo 'ユーザ名かパスワードが、ちがいます!<br>'; 21 echo '<a href="./login.php">ログイン画面</a>'; 22 exit; 23 } 24 } 25 26 $dsn = 'mysql:host=test;dbname=test_db;charset=utf8'; 27 $db_user = 'root'; 28 $db_pass = 'pass'; 29 $driver_options = [ 30 //オプション使用の際は追記 31 ]; 32 33 try { 34 $pdo = new PDO($dsn, $db_user, $db_pass, $driver_options); 35 } catch (PDOException $e) { 36 exit('DB接続失敗:' . $e->getMessage()); 37 } 38 39 $sql = 'SELECT id FROM test'; //「test」というテーブルからid一覧を取得 40 $stmt = $pdo->query($sql); 41 42 if(!$stmt){ 43 echo 'DBからのデータ取得にしっぱいしました・・・'; 44 exit; 45 } 46 47 $_SESSION['data'] = $stmt->fetchAll(PDO::FETCH_ASSOC); //「test」テーブルから取得したデータをb.phpへ渡すためセッション変数へ格納 48 header("Location: ./b.php");

b.php

1<?php 2 session_start(); 3 4 //DBから取得されているはずのデータを受け取っていない場合、ログイン画面へ戻る 5 if(!isset($_SESSION['data'])){ 6 header('Location: ./login.php'); 7 exit; 8 }else{ 9 echo '<pre>'; 10 var_dump($_SESSION['data']); 11 echo '</pre>'; 12 } 13 echo "a.phpで取得したDBのデータが正常に表示されました!";

気になったのはb.phpについてです。「$_SESSION['data']」には、a.phpにてDBから取得したデータが入っているはずなので、その内容を画面に表示する。そのような役割をb.phpは担っています。
そのため、もし「$_SESSION['data']」にデータがはいっていないということがもしあれば、そのときは異常事態なので、とりあえずログイン画面に強制遷移するようにしています。
しかし、a.php以外のページでもしも「$_SESSION['data']」にデータを入れた状態でb.phpに遷移された場合、意図せぬ形で画面表示が行われると考え、当質問のタイトルに「a.phpからb.phpに遷移したとき、a.phpから遷移したことを保証する手段」という内容を設定しました。
ただ、もし外部ページから「$_SESSION['data']」が渡されてそれがb.phpで表示されたとしても、特に実害が発生することはなさそう、という思いもあります!
したがいまして、そのような特例まではめんどうをみなくてもよいかもしれない、とも考えております。

上記内容を踏まえご意見頂戴できますと幸いです、よろしくお願いいたします!

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

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

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

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

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

guest

回答1

0

なぜ「想定しているページからの遷移しか許可しない」のか、その理由によって実装方法も変わります。ご指摘の方法だと、「かつてa.phpを閲覧したことがある」ということしか保証されません。それでよいのであれば、使えると思います。

セッションのキーと値を便宜上"a"としておりますが、このキーや値を複雑なものにするといいのかな、と考えました。

複雑なものにする必要はありません。セッションのキーや値は外部からは見えず、変更もできないからです。

しかし…もっと安全なやりかたが存在するのならばそれを知りたい!と考え質問を投稿させていただきました。

CSRFという脆弱性の対策にトークンというものを使う方法があり、まさに想定した遷移であることを確認する処理にはなるのですが、この場合の前提として、b.phpはPOSTメソッドにすべきであるのがありまして、リダイレクトに使うにはあまり適していません。

ということですので、やはり、「なぜそうしたいのか」が分かると、具体的な提案がしやすくなります。

投稿2022/10/05 12:48

ockeghem

総合スコア11701

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

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

y_programming

2022/10/05 13:06

徳丸先生、書き込みありがとうございます! のちほど質問文をもうすこし具体的にしようと思います、ご指摘下さりありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問