PHPについて質問です。


別ファイルのフォームよりPOSTで['keyword']を受け取り、
あらかじめ作成されている$keyword.phpというファイルに転送するという
趣旨で下記のようなスクリプトを作成しました。

$keyword = $_POST['keyword'];
header("location:$keyword.php");

上記のスクリプトを手直しする形で
必要なセキュリティ対策をすべて教えてください。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2008/11/03 15:07:19
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:pahoo No.3

回答回数5960ベストアンサー獲得回数633

ポイント50pt

こんな感じでどうでしょう。

なお、「必要なセキュリティ対策をすべて」というのは無理です。極端な話、PHPのバグまではフォローできませんので。

ただ、このスクリプト自体の欠陥に気づいた方がいましたら、遠慮無くご指摘ください。


■要件

  • form入力するのは http から始まるスクリプト名とする(ただし拡張子phpは除く)。
  • スクリプト名には ?(変数渡し) や #(ページ内ジャンプ)の指定はできない。
  • スクリプト名は http を含め255文字(半角)以内とする。
  • 送り手のスクリプト以外からのリクエストは受け付けない。(ブラウザでHTTP_REFERERを送信しない設定になっているとすべてエラーになる)
  • 自サイト以外のURLはエラーとする。
  • ジャンプする前に、念のため、当該コンテンツが存在するかどうかチェックする。

//HTTP_REFERERを調べる
$referer = 'http://www.hoge.com/送り手のスクリプト名';
if (strpos($_SERVER['HTTP_REFERER'], $referer) != 0) {
    echo 'ジャンプ元が間違っています';
    exit(1);
}
//念のためスクリプトの長さを制限する
$keyword = $_POST['keyword'];
if (strlen($keyword) > 255) {
    echo '指定されたコンテンツは長すぎます';
    exit(1);
}

//正しいURL書式かどうか調べる(?, # は除く)
preg_match("/(https?:\/\/localhost\/[\-_\.!~\*\'\(\)a-zA-Z0-9;\/:@&=+$,%]+)/", $keyword, $arr);

if (isset($arr[1])) {
    $fname = $arr[1];
    if (fopen($fname . '.php', 'r') == FALSE) {     //存在するかどうか調べる
                               //PHP5環境なのでfile_existsを使ってもいいかも
        echo '指定されたコンテンツ "' . $fname . '" は存在しません';
    } else {
        header("location: {$fname}.php");
    }
} else {
    echo 'コンテンツ "' . $keyword . '" は指定できません';
}
id:taroemon

ご回答ありがとうございます。

「必要なセキュリティ」というのがこんなにあるとは思いませんでした。

もちろんPHPのバグ修正までは望んでいません。

質問者としてはこれで十分満足しました。

2008/11/03 15:06:48

その他の回答2件)

id:pahoo No.1

回答回数5960ベストアンサー獲得回数633

ポイント10pt

確認ですが、POSTで受け取った変数が拡張子を除くスクリプト名 $keyword で、そのスクリプト $keyword.php にジャンプするという趣旨ですよね。


セキュリティ対策というのは、「予想される脅威から、何かを守る」ための対策です。

ご質問のケースでは、単純にジャンプするだけなので、守るべき「何か」は無いように思います。


$keyword 以外にも送信するデータがある、自サイト以外へはジャンプさせたくない等、もう少し具体的な要件をお示しください。

id:taroemon

ご回答ありがとうございます。

質問の説明不足申し訳ありません。


>確認ですが、POSTで受け取った変数が拡張子を除くスクリプト名 $keyword で、

>そのスクリプト $keyword.php にジャンプするという趣旨ですよね。

その通りです。


実際の送り手側はスクリプトは下記の通りです。

<form action="search.php" method='POST'>

<input type="text" name="keyword" size="30" value="">

<input type="submit" size="20" name="submit" value="検索">

</form>


$keyword 以外に送信するデータはありません

自サイト以外へはジャンプさせたくないです。


以上で適切な説明になってるでしょうか?

よろしくお願いします。

2008/11/03 10:59:55
id:b-wind No.2

回答回数3344ベストアンサー獲得回数440

ポイント23pt
$keyword = $_POST['keyword'];
$ok_keyword = array(
   'aaa' => 'http://www.example.com/aaa.php',
   'bbb' => 'http://www.example.com/bbb.php',
   'ccc' => 'http://www.example.com/ccc.php',
   'ddd' => 'http://www.example.com/ddd.php',
   'eee' => 'http://www.example.com/eee.php',
   'default' => 'http://www.example.com/aaa.php',
);
$url = $ok_keyword[$keyword] ? $ok_keyword[$keyword] : $ok_keyword['default']
header("location:$url");

突っ込みどころがありすぎて困るな。

@IT:Webアプリケーションに潜むセキュリティホール(14)

id:taroemon

これは検索されたとき、当該ファイル名が無い場合の処理ということでしょうか?

ご指摘ありがとうございます。

2008/11/03 11:03:45
id:pahoo No.3

回答回数5960ベストアンサー獲得回数633ここでベストアンサー

ポイント50pt

こんな感じでどうでしょう。

なお、「必要なセキュリティ対策をすべて」というのは無理です。極端な話、PHPのバグまではフォローできませんので。

ただ、このスクリプト自体の欠陥に気づいた方がいましたら、遠慮無くご指摘ください。


■要件

  • form入力するのは http から始まるスクリプト名とする(ただし拡張子phpは除く)。
  • スクリプト名には ?(変数渡し) や #(ページ内ジャンプ)の指定はできない。
  • スクリプト名は http を含め255文字(半角)以内とする。
  • 送り手のスクリプト以外からのリクエストは受け付けない。(ブラウザでHTTP_REFERERを送信しない設定になっているとすべてエラーになる)
  • 自サイト以外のURLはエラーとする。
  • ジャンプする前に、念のため、当該コンテンツが存在するかどうかチェックする。

//HTTP_REFERERを調べる
$referer = 'http://www.hoge.com/送り手のスクリプト名';
if (strpos($_SERVER['HTTP_REFERER'], $referer) != 0) {
    echo 'ジャンプ元が間違っています';
    exit(1);
}
//念のためスクリプトの長さを制限する
$keyword = $_POST['keyword'];
if (strlen($keyword) > 255) {
    echo '指定されたコンテンツは長すぎます';
    exit(1);
}

//正しいURL書式かどうか調べる(?, # は除く)
preg_match("/(https?:\/\/localhost\/[\-_\.!~\*\'\(\)a-zA-Z0-9;\/:@&=+$,%]+)/", $keyword, $arr);

if (isset($arr[1])) {
    $fname = $arr[1];
    if (fopen($fname . '.php', 'r') == FALSE) {     //存在するかどうか調べる
                               //PHP5環境なのでfile_existsを使ってもいいかも
        echo '指定されたコンテンツ "' . $fname . '" は存在しません';
    } else {
        header("location: {$fname}.php");
    }
} else {
    echo 'コンテンツ "' . $keyword . '" は指定できません';
}
id:taroemon

ご回答ありがとうございます。

「必要なセキュリティ」というのがこんなにあるとは思いませんでした。

もちろんPHPのバグ修正までは望んでいません。

質問者としてはこれで十分満足しました。

2008/11/03 15:06:48
  • id:taroemon
    書き忘れてましたが、
    Vista,PHP5、Firefoxという環境の元でやっています。
    よろしくお願いします。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません