他の何百もの回答/コメントが指摘しているように、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
%22
POST
現在のセットアップに対するこのタイプの攻撃に対する唯一の障害は、URI がルート相対であるため、常に「/」で始まることですが、最初の例が示すように、マルチバイト文字列を使用してブラウザーをだますことができます。結果のマークアップが壊れても、ほとんどのブラウザーの HTML パーサーが寛大であるため、リンクは引き続き機能します。この例は、あなたの質問を読んだ後、思い付くのに 15 分しかかかりませんでした。断固たる攻撃者であれば、実際に脅威となる何かを考え出すことは間違いありません。
安全のために、HTML と URL 用に特別に設計されたメソッドを使用して URI をサニタイズする必要があります。URL エスケープに関する OWASP のガイドラインは、開始するのに適した場所です。それ以外の場合は、ここの他の回答でより安全な代替手段が提供されます。