1

ログイン後、PHP を使用していたページにユーザーをリダイレクトしたいと考えています。この問題について少し調べてみましたが、良い解決策が見つからなかったので、$_SERVER['REQUEST_URI'] を使用して、現在の部分 URL を含む隠しフィールドをログイン フォームに追加することにしました。サーバーはこの情報を使用して、ログイン後にユーザーを前のページにリダイレクトします。これは正しく機能していますが、ここに私の質問があります。

全体として、サーバーに返された URL にどのようなセキュリティ対策を適用する必要がありますか?

例: フォームの値を $_SESSION['REQUEST_URI'] からhttp://www.google.comに変更すると、ログイン後に Google にリダイレクトされます。これを消毒する最良の方法は何ですか?

*現在、SQL インジェクションの目的で mysql_real_escape_string() を使用しています。

<form action="/signin/" method="post">
<input type="hidden" name="return" value="<?php echo $_SERVER['REQUEST_URI']; ?>" />
</form>
......
$return = mysql_real_escape_string($_POST['return']);
header('Location: '.$return);
4

4 に答える 4

2

他の何百もの回答/コメントが指摘しているように、mysqli今では誰もが使用しているはずです。それはさておき、 mysql_real_escape_string()名前が示すように、MySQL クエリで使用される文字列をエスケープするためのものです。それ以外の用途はありません。これから説明するように、XSS から保護することはできません...

設定:

// represent a string without using quotes
function ab($str) {
  $out = array();
  for ($i = 0; $i < strlen($str); $i++) {
    ($chr = _ab($str[$i])) || ($chr = 'String.fromCharCode('.ord($str[$i]).')');
  }
  return implode('+', $out);
}
// represent a character without quotes
function _ab($chr) { 
  $alpha = array(
    'Array', 'Boolean', 'Date', 'Function', 'Iterator', 'Number', 'Object',
    'RegExp', 'String', 'ArrayBuffer', 'Float32Array', 'Float64Array', 'JSON',
    'Int16Array', 'Int32Array', 'Int8Array', 'Uint16Array', 'Uint32Array',
    'Uint8Array', 'Uint8ClampedArray', 'Error', 'EvalError', 'InternalError',
    'RangeError', 'ReferenceError', 'StopIteration', 'SyntaxError', 'parseInt',
    'TypeError', 'URIError', 'decodeURI', 'decodeURIComponent', 'encodeURI',
    'encodeURIComponent', 'eval', 'isFinite', 'isNaN', 'parseFloat', 'uneval'
  );
  // sort function names by length to minimize output
  usort($alpha, function($a, $b){return strlen($a) - strlen($b);});
  foreach ($alpha as $fn) {
    if (($i = strpos($fn, $chr)) !== false) return "$fn.name[$i]";
  }
  return false;
}
$mb = chr(0xC2).chr(0x8F); // eats backslashes for breakfast

使い方:

$msg = ab('exploited!');
$payload = "console.log($msg);";
$uri = "$mb\" onmouseover=$payload title=XSS";
// try to sanitize URI
$uri = mysql_real_escape_string($uri);
?>
<a href="<?php echo $uri ?>">click me</a>

これにより、次のような「URI」が生成されます。

" onmouseover=console.log(Date.name[2]+eval.name[0]+isNaN.name[1]+Date.name[2]); title=hi

これはすり抜けますmysql_real_escape_string()(最初の「文字」は、実際には0xC28Fその直後の文字を食べる部分的なマルチバイト文字であるmysql_real_escape_string()ため、引用符をエスケープするためにバックスラッシュが挿入されます)。

<a href="\" onmouseover=THE_PAYLOAD title=XSS">click me</a>

ブラウザは次のように解釈します。

<a title="XSS"" onmouseover="THE_PAYLOAD" href="\">click me</a>

コンソールを開いた状態で Firefox または IE でこれを自分でテストできますmysql_real_escape_string()

mysql_real_escape_string()javascript:また、次のようなリンクからは保護されません。

javascript:$.post(%27/account/change-password%27,{newPassword:%27p0wned%27,newPassword2:%27p0wned%27});undefined;

MySQL ではパーセント エンコーディングが使用されていないため、それが単一引用符であるか二重引用符であるかはmysql_real_escape_string()わかりません。したがって、それらは無視されます。ユーザーがこのリンクをクリックすると、パスワードを攻撃者が選択したパスワードに変更するリクエストが送信されます。ユーザーが期待するページにリダイレクトするように変更することもできるため、ユーザーは何が起こったのかわかりません。%27%22POST

現在のセットアップに対するこのタイプの攻撃に対する唯一の障害は、URI がルート相対であるため、常に「/」で始まることですが、最初の例が示すように、マルチバイト文字列を使用してブラウザーをだますことができます。結果のマークアップが壊れても、ほとんどのブラウザーの HTML パーサーが寛大であるため、リンクは引き続き機能します。この例は、あなたの質問を読んだ後、思い付くのに 15 分しかかかりませんでした。断固たる攻撃者であれば、実際に脅威となる何かを考え出すことは間違いありません

安全のために、HTML と URL 用に特別に設計されたメソッドを使用して URI をサニタイズする必要があります。URL エスケープに関する OWASP のガイドラインは、開始するのに適した場所です。それ以外の場合は、ここの他の回答でより安全な代替手段が提供されます。

于 2012-08-03T11:11:07.313 に答える
1

のようなセッション変数に現在の URL を保存する必要が$_SESSION["last_page_visited"]あります (ログインおよびログイン送信ページを除く)。したがって、新しいページにアクセスするたび$_SESSION["last_page_visited"]に、現在の URL で上書きされます。そのため、どのページにアクセスしても、最後にアクセスしたページの URL がセッションに保存されます。また、どのページからでもログインをクリックすると、ログインが成功すると、そのセッションで保持されている URL にリダイレクトされます。$_SESSION["last_page_visited"] が空の場合、インデックス ページにリダイレクトします。

お役に立てれば。

于 2012-08-03T11:08:56.173 に答える
1

私はこれを見つけました。これは私にとって本当に良さそうです: PHPでOpen URLパラメーターを使用して安全にリダイレクトする

彼は、信頼できる「リファラー」のリストに取り組んでいます。

これを含め、いくつかの方法で作業できます。リファラー、フォームの非表示フィールド、および可能であればサーバーのログも確認します。

サーバーログを除いて、ユーザーがどこから来たのかを確認するより良い方法はないと思います.

于 2012-08-03T07:11:05.540 に答える
0

ログインページが SSL/TLS で暗号化されていて、サーバーから非表示のフォームフィールドの値を設定した場合 (ホワイトリストに対して検証済み)、送信前に変更された場合、ユーザーはそれを知っています。それ。

SSL/TLS がベスト プラクティスです。

于 2012-08-03T12:12:49.077 に答える