• 「GETパラメータ
    ーに不正な値が入っていないかチェック」する箇所で質問...
  • guest 
    「GETパラメーターに不正な値が入っていないかチェック」する箇所で質問があります。

    productDetail.php(21行目~)にて、

    if(empty($viewData)){
    error_log('エラー発生:指定ページに不正な値が入りました');
    header("Location:index.php"); //トップページへ
    }

    と、「$viewDataが空かどうか『のみ』」調べているのは何か理由がありますでしょうか?


    というのも、registProduct.php(35行目~)に「GETパラメータはあるが、改ざんされている(URLをいじくった)場合」

    if(!empty($p_id) && empty($dbFormData)){
    debug('GETパラメータの商品IDが違います。マイページへ遷移します。');
    header("Location:mypage.php"); //マイページへ
    }

    と「$_GET['p_id']がある場合」も指定されており、
    productDetail.phpでも、以下のようになるのではないか?と考えたからです。

    $p = (!empty($_GET['p'])) ? $_GET['p'] : '';
    $p_id = (!empty($_GET['p_id'])) ? $_GET['p_id'] : '';
    $viewData = getProductOne($p_id);
    if(!empty($p) && !empty($p_id) && empty($viewData)){
    error_log('不正な値がGETパラメーターに入りました');
    header("Location:index.php");
    }

    ただ、$_GET['p_id']、$_GET['p']にデータが入っているかどうかにかかわらず、
    「$viewDataにデータが入っていなければ、表示されない」というのも納得できます。


    こちらにつきまして、何か意図があって変えてあるのか、自分の見落としているところがあるかと思い、「GETパラメーター 改ざん」など調べてみましたが、納得できる回答はありませんでした。

    意図がある場合は、どういった理由か、ヒントをいただけますでしょうか。
    どうぞよろしくお願いいたします。
    回答 0

    guest 
    ①以上の質問につきまして、学習を進めるにつれ、$_GETに['c_id']['sort']も入る可能性があることが分かりました。

    確かに、条件式に、['c_id']['sort']['p']['p_id']があるかどうかたくさん指定しなくても、
    「$viewDataがあるかどうかだけを調べる」方が効率がいいような気もしてきました。


    ただ、その場合、逆に以下の条件式でも、「!empty($p_id) &&」は省略もできるのかなと考えましたが、こちらについては、意図ある差異だったでしょうか?

    ーーーー
    registProduct.php(35行目~)
    「GETパラメータはあるが、改ざんされている(URLをいじくった)場合」

    if(!empty($p_id) && empty($dbFormData)){
    debug('GETパラメータの商品IDが違います。マイページへ遷移します。');
    header("Location:mypage.php"); //マイページへ
    }
    ーーーー


    ②そして、お手数をおかけしますが、関連部分につきまして、もう一つ質問があります。

    「GETパラメーターに不正な値が入っていないかチェック」する条件式について、理解があっているか、ご教示いただければ、と思います。


    index.php 28行目付近「パラメーターに不正な値が入っていないかチェック」の部分で、
    上記とは異なる方法(「is_int」)で「$currentPage」を調べる方法があるのですが、
    (以下式です。)

    ーーーーー
    if(!is_int($currentPage)){
    error_log('エラー発生:指定ページに不適切な値が入りました。');
    header("Location:index.php");
    }
    ーーーーー

    registProduct.phpなどと異なる方法の条件式「is_int」を使っている理由としては、

    「・index.phpはだれでも見れるページだから(GETパラメーターの数字が他の整数に改ざんされたところで、プライベートなページではないので、問題ない)」
    「・GETパラメーターに整数が入ったところで、個人情報を抜き取られる恐れがないから」
    という理由でしょうか?

    (あくまで、本等調べた中での当方の推測です。検索してみたのですが、詳しいページがありませんでした…。)


    (試しに、条件部分を
    if(!empty($p) && empty($dbProductData['data'])
    と変えてみましたが、「productテーブルに登録のないcategoryで絞ったときに、全件表示されてしまう」というバグが発生してしまいました。)


    しばらくの間、考えたり調べていたのですが、
    「GETパラメーターへの挿入攻撃に関する条件式」について詳しいサイト等が見つかりませんでした。

    これからWebサービスを作っていくにあたり、パラメーター情報改ざんで情報が洩れると怖いため、
    以上に関しまして「どういった条件式を作成していけばいいのか」について、詳細を教えていただけますと幸いです。

    たくさん質問してしまい、お手数をおかけしますが、どうぞよろしくお願いいたします。

    ウェブカツコーチ 
    ①についてです。
    まずregistProduct.phpで!empty($p_id)をチェックしているのは、このページが商品登録と編集を兼ねていて、
    そのチェックでページが登録か編集か区別しているためです。
    商品登録のときはGETパラメータは空なので、編集ページのときのみempty($dbFormData)をチェックしたいがために!empty($p_id)を確認しています。
    (試しに!empty($p_id)という条件を消して商品登録ページにいこうとしてみてください。
    mypage.phpにとばされることがわかると思います。)
    一方でproductDetail.phpでは$p_idは必須なので!empty($p_id)を確認する必要はありません。
    $p_idが空だと自動的にif(!empty($viewData))に引っかかるためです。

    ②なぜ違う方法(is_int)でチェックしているのか
    index.phpのもう少し下の行を見てみましょう。
    $currentPageNum-1など、計算をしていますね。
    計算をするには数値でないといけないのでis_intでチェックしています。

    >「・index.phpはだれでも見れるページだから(GETパラメーターの数字が他の整数に改ざんされたところで、プライベートなページではないので、問題ない)」
    >「・GETパラメーターに整数が入ったところで、個人情報を抜き取られる恐れがないから」
    上記の通り、GETパラメータは数値の必要があり、
    他の整数に改ざんされても商品一覧ページが表示されるだけなので問題ありません。


    続いて、GETパラメータの改ざんについてもう少し説明します。
    GETパラメータを改ざんの問題は、そのパラメータにより見せてはいけないページが見えるなど期待していない動作が起きることです。
    その問題を防ぐために、
    まず、GETパラメータの値によってそのページの処理がどう変わるか場合分けして整理して、そのうちの望まない動作を把握します。
    そして、その望まない動作が起こらないように、その望まない動作が起こる条件となるパラメータが入力されたときにその望まない動作を防ぐように、
    おっしゃっている「GETパラメーターへの挿入攻撃に関する条件式」を考えて書いていきます。
    ですから、何か決まった万能の関数の形があるわけではありません。

    こちらについてregistProduct.phpで例えます。
    GETパラメータを変えると、他の商品データを編集できることになります。
    このページでは、他の商品とは「自分の登録した商品」と「他人が登録した商品」の二種類があります。
    自分の登録した商品は編集できて当然なのでいいですが、他人が登録した商品を編集できるのは危険ですよね?
    そこでregistProduct.phpの23行目あたりで、
    $dbFormData = (!empty($p_id)) ? getProduct($_SESSION['user_id'], $p_id) : '';
    ここではuser_idにひもづくproduct(商品)を取得しています。
    ここでGETパラメータを改ざんして、他人の商品データを取得しようとしても、
    getProduct($_SESSION['user_id'], $p_id)
    の結果が空となります。
    そのため、35行目付近で
    if(!empty($p_id) && empty($dbFormData)){
    と書いておけば、「GETパラメーターへの挿入攻撃」、今回の例でいう他人の商品の編集を防ぐことができます。

    guest 
    1つ1つ順を追って説明いただき、ありがとうございます。

    「GETパラメーターの挿入攻撃」には、何か決まった「型」があると思いこんでいたので、ドツボにはまっておりました。

    今回のコーチのご回答で、当件につきより理解が深まったため、自信をもってコードを書いていくことができそうです。

    今後とも、どうぞよろしくお願いいたします。