summaryrefslogtreecommitdiff
path: root/program/include
diff options
context:
space:
mode:
authorthomascube <thomas@roundcube.net>2011-12-10 01:33:58 +0000
committerthomascube <thomas@roundcube.net>2011-12-10 01:33:58 +0000
commit854397b216463d77561b8adadf880c3fbbcb8885 (patch)
treeb4d6668a0babad435dd9862c8d3109b18a54a336 /program/include
parent67e0c90fceb91d8b6c94275f96e6f1b80a9362bc (diff)
Better CSS url() validation
Diffstat (limited to 'program/include')
-rw-r--r--program/include/main.inc26
1 files changed, 20 insertions, 6 deletions
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;
}