1 function RemoveXSS($val) {
2 // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
3 // this prevents some character re-spacing such as <java\0script>
4 // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
5 $val = preg_replace(\'/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/\', \'\', $val);
6 // straight replacements, the user should never need these since they\'re normal characters
7 // this prevents like <IMG SRC=@avascript:alert(\'XSS\')>
8 $search = \'abcdefghijklmnopqrstuvwxyz\';
9 $search .= \'ABCDEFGHIJKLMNOPQRSTUVWXYZ\';
10 $search .= \'1234567890!@#$%^&*()\';
11 $search .= \'~`";:?+/={}[]-_|\\'\\\';
12 for ($i = 0; $i < strlen($search); $i++) {
13 // ;? matches the ;, which is optional
14 // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
15
16 // @ @ search for the hex values
17 $val = preg_replace(\'/(&#[xX]0{0,8}\'.dechex(ord($search[$i])).\';?)/i\', $search[$i], $val); // with a ;
18 // @ @ 0{0,7} matches \'0\' zero to seven times
19 $val = preg_replace(\'/(�{0,8}\'.ord($search[$i]).\';?)/\', $search[$i], $val); // with a ;
20 }
21
22 // now the only remaining whitespace attacks are \t, \n, and \r
23 $ra1 = array(\'javascript\', \'vbscript\', \'expression\', \'applet\', \'meta\', \'xml\', \'blink\', \'link\', \'style\', \'script\', \'embed\', \'object\', \'iframe\', \'frame\', \'frameset\', \'ilayer\', \'layer\', \'bgsound\', \'title\', \'base\');
24 $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\');
25 $ra = array_merge($ra1, $ra2);
26
27 $found = true; // keep replacing as long as the previous round replaced something
28 while ($found == true) {
29 $val_before = $val;
30 for ($i = 0; $i < sizeof($ra); $i++) {
31 $pattern = \'/\';
32 for ($j = 0; $j < strlen($ra[$i]); $j++) {
33 if ($j > 0) {
34 $pattern .= \'(\';
35 $pattern .= \'(&#[xX]0{0,8}([9ab]);)\';
36 $pattern .= \'|\';
37 $pattern .= \'|(�{0,8}([9|10|13]);)\';
38 $pattern .= \')*\';
39 }
40 $pattern .= $ra[$i][$j];
41 }
42 $pattern .= \'/i\';
43 $replacement = substr($ra[$i], 0, 2).\'<x>\'.substr($ra[$i], 2); // add in <> to nerf the tag
44 $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
45 if ($val_before == $val) {
46 // no replacements were made, so exit the loop
47 $found = false;
48 }
49 }
50 }
51 return $val;
52 }