제목 | xss_clean이 WYSIWYG의 style을 제거하는 부분 처리 | ||
---|---|---|---|
글쓴이 | 배강민 | 작성시각 | 2013/06/07 13:53:00 |
|
|||
그런데, CI의 xss_clean 이 style 도 xss 공격이 가능하므로 없애버리게 됩니다. 물론, 없애야 맞긴 하겠지만, 위지윅을 쓰려면 어쩔 수 없어서... style 이 안박히는 위지윅이 있는지 모르겠지만, 대부분 박히는듯... 해서 security.php 를 오버라이딩했습니다. application/core/MY_security.php 로 생성하면 되고요.. 사용은 forme_validation 에서는 xss_clean 을 빼고요. 만약 해당 변수가 $contents 라면 $this->security->xss_clean($contents, FALSE, TRUE); 로 하면 됩니다. 2번째 인자값은 원래 있는 값이고, 3번째가 TRUE 이면 wysiwyg 이므로 style 처리부분을 제거하겠다입니다. 좀 더 좋은 방법이 있을지 고민중이긴한데, 일단 공유드려봅니다. 더 좋은 의견을 기둘려보며...ㅋ <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class MY_Security extends CI_Security { public function __construct() { parent::__construct(); } /** * XSS Clean * * Sanitizes data so that Cross Site Scripting Hacks can be * prevented. This function does a fair amount of work but * it is extremely thorough, designed to prevent even the * most obscure XSS attempts. Nothing is ever 100% foolproof, * of course, but I haven't been able to get anything passed * the filter. * * Note: This function should only be used to deal with data * upon submission. It's not something that should * be used for general runtime processing. * * This function was based in part on some code and ideas I * got from Bitflux: http://channel.bitflux.ch/wiki/XSS_Prevention * * To help develop this script I used this great list of * vulnerabilities along with a few other hacks I've * harvested from examining vulnerabilities in other programs: * http://ha.ckers.org/xss.html * * @param mixed string or array * @param bool * @return string */ public function xss_clean($str, $is_image = FALSE, $is_wysiwyg = FALSE) { /* * Is the string an array? * */ if (is_array($str)) { while (list($key) = each($str)) { $str[$key] = $this->xss_clean($str[$key]); } return $str; } /* * Remove Invisible Characters */ $str = remove_invisible_characters($str); // Validate Entities in URLs $str = $this->_validate_entities($str); /* * URL Decode * * Just in case stuff like this is submitted: * * <a href="http://www.google.com">Google</a> * * Note: Use rawurldecode() so it does not remove plus signs * */ $str = rawurldecode($str); /* * Convert character entities to ASCII * * This permits our tests below to work reliably. * We only convert entities that are within tags since * these are the ones that will pose security problems. * */ $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str); $str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, '_decode_entity'), $str); /* * Remove Invisible Characters Again! */ $str = remove_invisible_characters($str); /* * Convert all tabs to spaces * * This prevents strings like this: javascript * NOTE: we deal with spaces between characters later. * NOTE: preg_replace was found to be amazingly slow here on * large blocks of data, so we use str_replace. */ if (strpos($str, "\t") !== FALSE) { $str = str_replace("\t", ' ', $str); } /* * Capture converted string for later comparison */ $converted_string = $str; // Remove Strings that are never allowed $str = $this->_do_never_allowed($str); /* * Makes PHP tags safe * * Note: XML tags are inadvertently replaced too: * * <?xml * * But it doesn't seem to pose a problem. */ if ($is_image === TRUE) { // Images have a tendency to have the PHP short opening and // closing tags every so often so we skip those and only // do the long opening tags. $str = preg_replace('/<\?(php)/i', "<?\\1", $str); } else { $str = str_replace(array('<?', '?'.'>'), array('<?', '?>'), $str); } /* * Compact any exploded words * * This corrects words like: javascript * These words are compacted back to their correct state. */ $words = array( 'javascript', 'expression', 'vbscript', 'script', 'base64', 'applet', 'alert', 'document', 'write', 'cookie', 'window' ); foreach ($words as $word) { $temp = ''; for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++) { $temp .= substr($word, $i, 1)."\s*"; } // We only want to do this when it is followed by a non-word character // That way valid stuff like "dealer to" does not become "dealerto" $str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str); } /* * Remove disallowed Javascript in links or img tags * We used to do some version comparisons and use of stripos for PHP5, * but it is dog slow compared to these simplified non-capturing * preg_match(), especially if the pattern exists in the string */ do { $original = $str; if (preg_match("/<a/i", $str)) { $str = preg_replace_callback("#<a\s+([^>]*?)(>|$)#si", array($this, '_js_link_removal'), $str); } if (preg_match("/<img/i", $str)) { $str = preg_replace_callback("#<img\s+([^>]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str); } if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str)) { $str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str); } } while($original != $str); unset($original); // Remove evil attributes such as style, onclick and xmlns $str = $this->_remove_evil_attributes($str, $is_image, $is_wysiwyg); /* * Sanitize naughty HTML elements * * If a tag containing any of the words in the list * below is found, the tag gets converted to entities. * * So this: <blink> * Becomes: <blink> */ $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss'; $str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str); /* * Sanitize naughty scripting elements * * Similar to above, only instead of looking for * tags it looks for PHP and JavaScript commands * that are disallowed. Rather than removing the * code, it simply converts the parenthesis to entities * rendering the code un-executable. * * For example: eval('some code') * Becomes: eval('some code') */ $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2(\\3)", $str); // Final clean up // This adds a bit of extra precaution in case // something got through the above filters $str = $this->_do_never_allowed($str); /* * Images are Handled in a Special Way * - Essentially, we want to know that after all of the character * conversion is done whether any unwanted, likely XSS, code was found. * If not, we return TRUE, as the image is clean. * However, if the string post-conversion does not matched the * string post-removal of XSS, then it fails, as there was unwanted XSS * code found and removed/changed during processing. */ if ($is_image === TRUE) { return ($str == $converted_string) ? TRUE: FALSE; } log_message('debug', "XSS Filtering completed"); return $str; } // -------------------------------------------------------------------- /* * Remove Evil HTML Attributes (like evenhandlers and style) * * It removes the evil attribute and either: * - Everything up until a space * For example, everything between the pipes: * <a |style=[removed]('hello');alert('world');| class=link> * - Everything inside the quotes * For example, everything between the pipes: * <a |style="[removed]('hello'); alert('world');"| class="link"> * * @param string $str The string to check * @param boolean $is_image TRUE if this is an image * @return string The string with the evil attributes removed */ protected function _remove_evil_attributes($str, $is_image, $is_wysiwyg) { // All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns $evil_attributes = array('on\w*', 'style', 'xmlns', 'formaction'); if($is_wysiwyg === TRUE) { unset($evil_attributes[1]); //wysiwyg 인 경우 style 처리 제외 } if ($is_image === TRUE) { /* * Adobe Photoshop puts XML metadata into JFIF images, * including namespacing, so we have to allow this for images. */ unset($evil_attributes[array_search('xmlns', $evil_attributes)]); } do { $count = 0; $attribs = array(); // find occurrences of illegal attribute strings without quotes preg_match_all('/('.implode('|', $evil_attributes).')\s*=\s*([^\s>]*)/is', $str, $matches, PREG_SET_ORDER); foreach ($matches as $attr) { $attribs[] = preg_quote($attr[0], '/'); } // find occurrences of illegal attribute strings with quotes (042 and 047 are octal quotes) preg_match_all("/(".implode('|', $evil_attributes).")\s*=\s*(\042|\047)([^\\2]*?)(\\2)/is", $str, $matches, PREG_SET_ORDER); foreach ($matches as $attr) { $attribs[] = preg_quote($attr[0], '/'); } // replace illegal attribute strings that are inside an html tag if (count($attribs) > 0) { $str = preg_replace("/<(\/?[^><]+?)([^A-Za-z<>\-])(.*?)(".implode('|', $attribs).")(.*?)([\s><])([><]*)/i", '<$1 $3$5$6$7', $str, -1, $count); } } while ($count); return $str; } } //EOF |
|||
다음글 | 폼검증에서 select 박스 값 복원 (2) | ||
이전글 | 사진정보 읽고 쓰기 | ||
배강민
/
2013/06/07 13:56:32 /
추천
0
단순히 파라메터 추가하고, style만 처리대상 배열에서 빼버립니다.
|
criuce
/
2013/06/07 23:29:23 /
추천
0
그런데 style 안에 javascript를 넣어도 동작을 하게 되는데, style을 예외처리하면 xss_clean 자체가 의미가 없어질 것 같아요.
|
배강민
/
2013/06/08 13:46:14 /
추천
0
그렇긴하죠. 근데 그럴라면 일반적인 위지윅을 쓰지 말던가 style을 포기하던가 style이 안박히는 위지윅을 찾던가 만들던가 해야하는 상황이란게 문제죠...쩝..
좀 뒤져봐도 대부분 xss_clean 을 포기해버리던데, 그래도 style만 빼고는 써보고자 해봤던... |