From 854397b216463d77561b8adadf880c3fbbcb8885 Mon Sep 17 00:00:00 2001 From: thomascube Date: Sat, 10 Dec 2011 01:33:58 +0000 Subject: Better CSS url() validation --- CHANGELOG | 1 + program/include/main.inc | 26 ++++++++++++++++++++------ program/steps/mail/func.inc | 4 ++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7cfb358f9..710e6d6d9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Make Roundcube render the Email Standards Project Acid Test correctly - Deprecate $DB, $USER, $IMAP global variables, Use $RCMAIL instead - Add option to set default font for HTML message (#1484137) - Fix issues with big memory allocation of IMAP results diff --git a/program/include/main.inc b/program/include/main.inc index 2d18567e7..372e966ef 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -891,15 +891,29 @@ function rcmail_mod_css_styles($source, $container_id, $allow_remote=false) // ignore the whole block if evil styles are detected $source = rcmail_xss_entity_decode($source); $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); - $evilexpr = 'expression|behavior' . (!$allow_remote ? '|url\(|import[^a]' : ''); - if (preg_match("/$evilexpr/i", $stripped) // don't accept No-Gos - || (strpos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Ui', $source))) // only allow clean urls + $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : ''); + if (preg_match("/$evilexpr/i", $stripped)) return '/* evil! */'; // cut out all contents between { and } - while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) - { - $key = $replacements->add(substr($source, $pos+1, $pos2-($pos+1))); + while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { + $styles = substr($source, $pos+1, $pos2-($pos+1)); + + // check every line of a style block... + if ($allow_remote) { + $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY); + foreach ($a_styles as $line) { + $stripped = preg_replace('/[^a-z\(:;]/i', '', $line); + // ... and only allow strict url() values + if (stripos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims', $line)) { + $a_styles = array('/* evil! */'); + break; + } + } + $styles = join(";\n", $a_styles); + } + + $key = $replacements->add($styles); $source = substr($source, 0, $pos+1) . $replacements->get_replacement($key) . substr($source, $pos2, strlen($source)-$pos2); $last_pos = $pos+2; } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index a0a4dcab7..2bc0091cb 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -834,8 +834,8 @@ function rcmail_washtml_callback($tagname, $attrib, $content, $washtml) $stripped = preg_replace('/[^a-zA-Z\(:;]/', '', rcmail_xss_entity_decode($content)); // now check for evil strings like expression, behavior or url() - if (!preg_match('/expression|behavior/i', $stripped)) { - if (!$washtml->get_config('allow_remote') && preg_match('/url\(|import[^a]/i', $stripped)) + if (!preg_match('/expression|behavior|javascript:|import[^a]/i', $stripped)) { + if (!$washtml->get_config('allow_remote') && stripos($stripped, 'url(')) $washtml->extlinks = true; else $out = html::tag('style', array('type' => 'text/css'), $content); -- cgit v1.2.3