написал парсер html тегов для сайта. Помогите проверить уязвимости. Наверное написан коряво... ну я пхп не долго изучаю. Code: class chu_parser { function parse($text) { $text = htmlspecialchars(trim(str_replace("\0", "", $text)), ENT_NOQUOTES); $zapret_params = array("test", "codetype", 'style', 'action', 'onAbort', 'onBlur', 'onChange', 'onClick', 'onDblClick', 'onError', 'onFocus', 'onKeyDown', 'onKeyPress', 'onKeyUp', 'onLoad', 'onMouseDown', 'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp', 'onMove', 'onReset', 'onResize', 'onSelect', 'onSubmit', 'onUnload'); // плохие параметры $bad_attrvals = array("javascript:", "data:", "test:", "behavior:", "vbscript:", "mocha:", "livescript:", "shadow", "shbox", "shinfo", "sherror", "left", "right", "menulab", "menu2", "detached"); // плохие значения параметров $bad_attrvals_str = $this->arr2str($bad_attrvals, '|'); // подготовим для preg_match $allow_tags = array('b', 'div', 'hr', 'img', 'code', 'bkb', 'tt', 'table', 'tr', 'td', 'font', 'center', 'link', 'embed', 'object', 'quote', 'marquee', 'sup', 'sup', 'effect', 'param', 'i', 'li', 'ol', 's', 'u', 'blink'); $pattern = "#<([a-z]+)( .*)?(?!/)>#iU"; preg_match_all($pattern, $text, $matches); $all_full_tags = $matches[0]; //все полные теги foreach ($matches[1] as $value) { $new_tags_params[][$value] = array(); } for ($k = 0; $k < count($matches[2]); $k++) { $value = $matches[2][$k]; // заменям кавычки на стандартные $value = str_ireplace("'", '"', $value); // удаляем лишние пробелы $value = str_ireplace(' ', '', $value); $value = str_ireplace('"', '" ', $value); $value = str_ireplace('=\" ', '=\"', $value); //================ $val_arr = $this->del_null_in_arr(explode(' ', $value)); $new_2_val_arr = array(); if ($val_arr) { foreach ($val_arr as $val) { $new_val_arr = $this->del_null_in_arr(explode('=', $val)); if ($new_val_arr) { $new_val_arr[1] = str_ireplace('\"', '', $new_val_arr[1]); //$new_val_arr[1] = str_ireplace("\'", '', $new_val_arr[1]); $new_2_val_arr[$new_val_arr[0]] = $new_val_arr[1]; } } } $new_tags_params[$k][$matches[1][$k]] = $new_2_val_arr; } //======= теперь тут нормальный архив с тегами, затем проверяем разрешенность тегов и параметров if ($new_tags_params) { for ($k = 0; $k < count($new_tags_params); $k++) { foreach ($new_tags_params[$k] as $tag_name => $param_arr) { if (!in_array($tag_name, $allow_tags)) $new_tags_params[$k][] = 'banned'; // если тега нет среди разрешенных if ($param_arr) { foreach ($param_arr as $param_name => $param_value) { if (in_array($param_name, $zapret_params) || preg_match("/($bad_attrvals_str)/i", $param_value)) $new_tags_params[$k][] = 'banned'; // если параметр тега или его значение запрещено } } } } //============= теперь создаём обратно теги с параметрами for ($k = 0; $k < count($new_tags_params); $k++) { foreach ($new_tags_params[$k] as $tag_name => $param_arr) { if ($tag_name != '0' && $tag_name != '1') { $tag = "<$tag_name"; if ($param_arr) { foreach ($param_arr as $param_name => $param_value) { $tag .= " $param_name=\"$param_value\""; } } $tag.=">"; if ($new_tags_params[$k][0] == 'banned') { $tag = htmlspecialchars($tag); } $new_tags[0][$k] = $tag; if ($new_tags_params[$k][0] != 'banned') { $new_tags[1][$k] = $tag_name; } } } } //============ теперь вставляем обратно теги if ($new_tags) { //$html_new_tags = htmlentities_arr($new_tags); for ($k = 0; $k < count($new_tags[0]); $k++) { $text = str_ireplace($all_full_tags[$k], $new_tags[0][$k], $text); } } //============= теперь закрываем все теги preg_match_all("#</([a-z]+)>#iU", $text, $matches); // все закрывающие теги for ($k = 0; $k < count($matches[1]); $k++) { if (in_array($matches[1][$k], $new_tags[1])) { $num = 1; $search = array_search($matches[1][$k], $new_tags[1]); $text = str_replace($matches[0][$k], '</' . $new_tags[1][$search] . '>', $text, $num); unset($new_tags[1][$search]); } } //========================== } return $text; } function del_null_in_arr($arr) { foreach ($arr as $value) { if (trim($value) != '') { $new_arr[] = $value; } } return $new_arr; } //делает из массива строку с разделителями function arr2str($arr, $str) { for ($i = 0; $i < count($arr); $i++) { if ($i + 1 < count($arr)) { $new_str .= $arr[$i] . $str; } else { $new_str .= $arr[$i]; } } return $new_str; } }
Лучше вообше запретить все атрибуты начинающиеся на on иначе за всеми не уследишь. onmouseenter onscroll например пропущены и еще оно кучу ошибок выдает, из-за необъявленных переменных. несмертельно но тестировать тяжело.
ну у меня на денвере ошибок из-за переменных нет, но объявлю все, спасибо. ещё нашел, что теги не закрытые юзером не закрываются.