/** * Detects typical XSS attack patterns * @param string str String to search for XSS attack vectors * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images. * @return array Array of matches, empty on clean string */ function clean_xss($str, $cleanImg = true) { global $sugar_config; if (empty($sugar_config['email_xss'])) { $sugar_config['email_xss'] = getDefaultXssTags(); } $arr = unserialize(base64_decode($sugar_config['email_xss'])); $regex = ''; foreach ($arr as $v) { if (!empty($regex)) { $regex .= "|"; } $regex .= $v; } $tag_regex = "#<({$regex})[^>]*>?#sim"; // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.) $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|"; $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|"; $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop"; $attribute_regex = "#<.+({$jsEvents})[^=>]*=[^>]*>#sim"; $javascript_regex = '@<[^/>][^>]+(expression\\(|j\\W*a\\W*v\\W*a|v\\W*b\\W*s\\W*c\\W*r|&#|/\\*|\\*/)[^>]*>@sim'; $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim'; $css_url = '#url\\(.*\\.\\w+\\)#'; $str = str_replace("\t", "", $str); $matches = array_merge(xss_check_pattern($tag_regex, $str), xss_check_pattern($javascript_regex, $str)); $jsMatches = xss_check_pattern($attribute_regex, $str); if (!empty($jsMatches)) { preg_match_all($attribute_regex, $str, $newMatches, PREG_PATTERN_ORDER); if (!empty($newMatches[0][0])) { $matches2 = array_merge(xss_check_pattern("#({$jsEvents})#sim", $newMatches[0][0])); $matches = array_merge($matches, $matches2); } } if ($cleanImg) { $matches = array_merge($matches, xss_check_pattern($imgsrc_regex, $str)); } // cn: bug 13498 - custom white-list of allowed domains that vet remote images preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER); if (isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) { if (is_array($cssUrlMatches) && count($cssUrlMatches) > 0) { // normalize whitelist foreach ($sugar_config['security_trusted_domains'] as $k => $v) { $sugar_config['security_trusted_domains'][$k] = strtolower($v); } foreach ($cssUrlMatches[0] as $match) { $domain = strtolower(substr(strstr($match, "://"), 3)); $baseUrl = substr($domain, 0, strpos($domain, "/")); if (!in_array($baseUrl, $sugar_config['security_trusted_domains'])) { $matches[] = $match; } } } } else { $matches = array_merge($matches, $cssUrlMatches[0]); } return $matches; }
/** * Detects typical XSS attack patterns * @deprecated * @param string str String to search for XSS attack vectors * @param bool cleanImg Flag to allow <img> tags to survive - only used by InboundEmail for inline images. * @return array Array of matches, empty on clean string */ function clean_xss($str, $cleanImg = true) { global $sugar_config; if (empty($sugar_config['email_xss'])) { $sugar_config['email_xss'] = getDefaultXssTags(); } $xsstags = unserialize(base64_decode($sugar_config['email_xss'])); // cn: bug 13079 - "on\w" matched too many non-events (cONTact, strONG, etc.) $jsEvents = "onblur|onfocus|oncontextmenu|onresize|onscroll|onunload|ondblclick|onclick|"; $jsEvents .= "onmouseup|onmouseover|onmousedown|onmouseenter|onmouseleave|onmousemove|onload|onchange|"; $jsEvents .= "onreset|onselect|onsubmit|onkeydown|onkeypress|onkeyup|onabort|onerror|ondragdrop"; $attribute_regex = "#\\b({$jsEvents})\\s*=\\s*(?|(?!['\"])\\S+|['\"].+?['\"])#sim"; $javascript_regex = '@<[^/>][^>]+(expression\\(|j\\W*a\\W*v\\W*a|v\\W*b\\W*s\\W*c\\W*r|&#|/\\*|\\*/)[^>]*>@sim'; $imgsrc_regex = '#<[^>]+src[^=]*=([^>]*?http(s)?://[^>]*)>#sim'; $css_url = '#url\\(.*\\.\\w+\\)#'; $tagsrex = '#<\\/?(\\w+)((?:\\s+(?:\\w|\\w[\\w-]*\\w)(?:\\s*=\\s*(?:\\".*?\\"|\'.*?\'|[^\'\\">\\s]+))?)+\\s*|\\s*)\\/?>#im'; $tagmatches = array(); $matches = array(); preg_match_all($tagsrex, $str, $tagmatches, PREG_PATTERN_ORDER); foreach ($tagmatches[1] as $no => $tag) { if (in_array($tag, $xsstags)) { // dangerous tag - take out whole $matches[] = $tagmatches[0][$no]; continue; } $attrmatch = array(); preg_match_all($attribute_regex, $tagmatches[2][$no], $attrmatch, PREG_PATTERN_ORDER); if (!empty($attrmatch[0])) { $matches = array_merge($matches, $attrmatch[0]); } } $matches = array_merge($matches, xss_check_pattern($javascript_regex, $str)); if ($cleanImg) { $matches = array_merge($matches, xss_check_pattern($imgsrc_regex, $str)); } // cn: bug 13498 - custom white-list of allowed domains that vet remote images preg_match_all($css_url, $str, $cssUrlMatches, PREG_PATTERN_ORDER); if (isset($sugar_config['security_trusted_domains']) && !empty($sugar_config['security_trusted_domains']) && is_array($sugar_config['security_trusted_domains'])) { if (is_array($cssUrlMatches) && count($cssUrlMatches) > 0) { // normalize whitelist foreach ($sugar_config['security_trusted_domains'] as $k => $v) { $sugar_config['security_trusted_domains'][$k] = strtolower($v); } foreach ($cssUrlMatches[0] as $match) { $domain = strtolower(substr(strstr($match, "://"), 3)); $baseUrl = substr($domain, 0, strpos($domain, "/")); if (!in_array($baseUrl, $sugar_config['security_trusted_domains'])) { $matches[] = $match; } } } } else { $matches = array_merge($matches, $cssUrlMatches[0]); } return $matches; }