実はこの話題についてずっと前から話したいと思っていたのですが、国内の PHP サイトの多くに XSS の脆弱性があることが分かりました。今日は偶然PHP5のXSS脆弱性を発見したので、ここでまとめておきたいと思います。ちなみに、PHP5を使用している友人はパッチを適用するかアップグレードするのが最善です。
XSS が何なのかわからない場合は、ここまたはここを読んでください (中国語版の方がわかりやすいかもしれません)。
多くの国内フォーラムにはクロスサイトスクリプティングの脆弱性があります。たとえば、Discuz 4.0.0RC3 をターゲットとした Google Hack+XSS 攻撃の例を次に示します。海外ではこのような例が多く、Googleでも出てきましたが、12月上旬に修正されました。クロスサイト攻撃は簡単に構築できますが、非常に巧妙で検出が困難です (通常は情報を盗み、すぐに元のページに戻ります)。
攻撃方法についてはここでは説明しません(質問しないでください)。主に攻撃を防ぐ方法について話します。まず、クロスサイト スクリプティング攻撃はユーザー入力の厳密なフィルタリングが欠如していることが原因で発生するため、すべてのデータが Web サイトやデータベースに入力される前に、起こり得る危険を阻止する必要があります。一重引用符や二重引用符を含む不正な HTML コードの場合は、htmlentities() を使用できます。
$str = "A 'quote' is bold";
// 出力: A 'quote' is bold ($str);
// 出力: 'quote' は bold
echo htmlentities($str,
?>); これにより、不正なスクリプトが無効になります。
ただし、htmlentities() のデフォルトのエンコードは ISO-8859-1 であることに注意してください。不正なスクリプトが他の形式でエンコードされている場合、フィルタリングされない可能性がありますが、ブラウザはそれを認識して実行できます。この問題について話す前に、まずこの問題をテストするためのサイトをいくつか見つけます。
这里提供一过滤非法書的関数:
function RemoveXSS($val) {
// すべての印刷不可能な文字を削除します。 CR(0a)、LF(0b)、TAB(9) は許可されます
//これにより、
// n、r、t による分割は、一部の入力では*許可されている*ため、後で処理する必要があることに注意してください。
$val = preg_replace('/([x00-x08][x0b-x0c][x0e-x20] ])/', '', $val);
// ストレートな置換。これらは通常の文字であるため、ユーザーはこれらを必要としません
//これにより、
$search = 'abcdefghijklmnopqrstuvwxyz';
$search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$search .= '1234567890!@#$%^&*()';
$search .= '~`";:?+/={}[]-_|'\';
for ($i = 0; $i < strlen($search); $i++) {
/ / ;? ; に一致します。これはオプションです
//0{0,7} は、任意の埋め込まれたゼロに一致し、最大 8 文字になります
//@ @ 16 進数の値を検索します
$val = preg_replace('/([x|X]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val ); // a ; // @ @ 0{0,7} 「0」 0 ~ 7 回一致
$val = preg_replace('/({0,8}'.ord search[$i]).';?)/', $search[$i], $val); // a ; }
// 現在、残っているホワイトスペース攻撃は t、n、r のみです
$ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink' 、「リンク」、「スタイル」、「スクリプト」、「埋め込み」、「オブジェクト」、「iframe」、「フレーム」、「フレームセット」、「ilayer」、「レイヤー」、「bgsound」、「タイトル」、」ベース');
$ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload'、'onbeforeupdate'、'onblur'、'onbounce'、'oncellchange'、'onchange'、'onclick'、'oncontextmenu'、'oncontrolselect'、'oncopy'、'oncut'、'ondataavailable'、'ondatasetchanged ', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange'、'onfinish'、'onfocus'、'onfocusin'、'onfocusout'、'onhelp'、'onkeydown'、'onkeypress'、'onkeyup'、'onlayoutcomplete'、'onload'、'onlosecapture'、'onmousedown '、'onmouseenter'、'onmouseleave'、'onmousemove'、'onmouseout'、'onmouseover'、'onmouseup'、'onmousewheel'、'onmove'、'onmoveend'、'onmovestart'、'onpaste'、'onpropertychange'、 'onreadystatechange'、'onreset'、'onresize'、'onresizeend'、'onresizestart'、'onrowenter'、'onrowexit'、'onrowsdelete'、'onrowsinserted'、'onscroll'、'onselect'、'onselectionchange'、'onselectstart '、'onstart'、'onstop'、'onsubmit'、'onunload');
$ra = array_merge($ra1, $ra2);
$found = true; // 前回のラウンドで何かが置き換えられている限り、置き換えを続けます
while ($found == true) {
$val_before = $val;
for ($i = 0; $i < sizeof($ra); $i++) {
$pattern = '/';
for ($j = 0; $j
$pattern .= '(';
$pattern .= '([x|X]0{0,8}([9][a][b]);?)?';
$pattern .= '|({0,8}([ 9][10][13]);?)?';
$pattern .= ')?';
}
$pattern .= $ra[$i][$j];
}
$pattern .= '/i';
$replacement = substr($ra[$i], 0, 2).'
$val = preg_replace($pattern, $replacement, $val); // 16 進タグをフィルタリングします
if ($val_before == $val) {
// 置換が行われなかったため、ループを終了します
$found = false;
}
}
}
}