Changeset 5591 in subversion


Ignore:
Timestamp:
Dec 10, 2011 9:16:31 AM (18 months ago)
Author:
thomasb
Message:

Backported CSS sanitization (r5586:r5590)

Location:
branches/release-0.7
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/release-0.7/CHANGELOG

    r5582 r5591  
    44RELEASE 0.7 
    55----------- 
     6- Make Roundcube render the Email Standards Project Acid Test correctly 
    67- Replace prompt() with jQuery UI dialog (#1485135) 
    78- Fix navigation in messages search results 
  • branches/release-0.7/program/include/main.inc

    r5499 r5591  
    884884 * @return string Modified CSS source 
    885885 */ 
    886 function rcmail_mod_css_styles($source, $container_id) 
     886function rcmail_mod_css_styles($source, $container_id, $allow_remote=false) 
    887887  { 
    888888  $last_pos = 0; 
     
    890890 
    891891  // ignore the whole block if evil styles are detected 
    892   $stripped = preg_replace('/[^a-z\(:;]/', '', rcmail_xss_entity_decode($source)); 
    893   if (preg_match('/expression|behavior|url\(|import[^a]/', $stripped)) 
     892  $source = rcmail_xss_entity_decode($source); 
     893  $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); 
     894  $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : ''); 
     895  if (preg_match("/$evilexpr/i", $stripped)) 
    894896    return '/* evil! */'; 
    895897 
    896   // remove css comments (sometimes used for some ugly hacks) 
    897   $source = preg_replace('!/\*(.+)\*/!Ums', '', $source); 
    898  
    899898  // cut out all contents between { and } 
    900   while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) 
    901   { 
    902     $key = $replacements->add(substr($source, $pos+1, $pos2-($pos+1))); 
     899  while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { 
     900    $styles = substr($source, $pos+1, $pos2-($pos+1)); 
     901 
     902    // check every line of a style block... 
     903    if ($allow_remote) { 
     904      $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY); 
     905      foreach ($a_styles as $line) { 
     906        $stripped = preg_replace('/[^a-z\(:;]/i', '', $line); 
     907        // ... and only allow strict url() values 
     908        if (stripos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims', $line)) { 
     909          $a_styles = array('/* evil! */'); 
     910          break; 
     911        } 
     912      } 
     913      $styles = join(";\n", $a_styles); 
     914    } 
     915 
     916    $key = $replacements->add($styles); 
    903917    $source = substr($source, 0, $pos+1) . $replacements->get_replacement($key) . substr($source, $pos2, strlen($source)-$pos2); 
    904918    $last_pos = $pos+2; 
     
    938952  $out = html_entity_decode(html_entity_decode($content)); 
    939953  $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entity_decode_callback', $out); 
    940   $out = preg_replace('#/\*.*\*/#Um', '', $out); 
     954  $out = preg_replace('#/\*.*\*/#Ums', '', $out); 
    941955  return $out; 
    942956} 
  • branches/release-0.7/program/lib/washtml.php

    r5514 r5591  
    169169              $value .= ' url('.htmlspecialchars($src, ENT_QUOTES) . ')'; 
    170170            } 
    171             else if (preg_match('/^(http|https|ftp):.*$/i', $match[2], $url)) { 
     171            else if (preg_match('!^(https?:)?//[a-z0-9/._+-]+$!i', $match[2], $url)) { 
    172172              if ($this->config['allow_remote']) 
    173173                $value .= ' url('.htmlspecialchars($url[0], ENT_QUOTES).')'; 
     
    244244        $tagName = strtolower($node->tagName); 
    245245        if ($callback = $this->handlers[$tagName]) { 
    246           $dump .= call_user_func($callback, $tagName, $this->wash_attribs($node), $this->dumpHtml($node)); 
     246          $dump .= call_user_func($callback, $tagName, $this->wash_attribs($node), $this->dumpHtml($node), $this); 
    247247        } 
    248248        else if (isset($this->_html_elements[$tagName])) { 
     
    302302  } 
    303303 
     304  /** 
     305   * Getter for config parameters 
     306   */ 
     307  public function get_config($prop) 
     308  { 
     309      return $this->config[$prop]; 
     310  } 
     311 
    304312} 
    305313 
  • branches/release-0.7/program/steps/mail/func.inc

    r5527 r5591  
    822822 * Callback function for washtml cleaning class 
    823823 */ 
    824 function rcmail_washtml_callback($tagname, $attrib, $content) 
     824function rcmail_washtml_callback($tagname, $attrib, $content, $washtml) 
    825825{ 
    826826  switch ($tagname) { 
     
    834834 
    835835      // now check for evil strings like expression, behavior or url() 
    836       if (!preg_match('/expression|behavior|url\(|import[^a]/', $stripped)) { 
    837         $out = html::tag('style', array('type' => 'text/css'), $content); 
     836      if (!preg_match('/expression|behavior|javascript:|import[^a]/i', $stripped)) { 
     837        if (!$washtml->get_config('allow_remote') && stripos($stripped, 'url(')) 
     838          $washtml->extlinks = true; 
     839        else 
     840          $out = html::tag('style', array('type' => 'text/css'), $content); 
    838841        break; 
    839842      } 
     
    10151018 
    10161019        if ($part->ctype_secondary == 'html') { 
    1017           $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs); 
     1020          $body = rcmail_html4inline($body, $attrib['id'], 'rcmBody', $attrs, $safe_mode); 
    10181021          $div_attr = array('class' => 'message-htmlpart'); 
    10191022          $style = array(); 
     
    10891092 * modify a HTML message that it can be displayed inside a HTML page 
    10901093 */ 
    1091 function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null) 
     1094function rcmail_html4inline($body, $container_id, $body_id='', &$attributes=null, $allow_remote=false) 
    10921095{ 
    10931096  $last_style_pos = 0; 
     
    11021105    // replace all css definitions with #container [def] 
    11031106    $styles = rcmail_mod_css_styles( 
    1104       substr($body, $pos, $pos2-$pos), $cont_id); 
     1107      substr($body, $pos, $pos2-$pos), $cont_id, $allow_remote); 
    11051108 
    11061109    $body = substr($body, 0, $pos) . $styles . substr($body, $pos2); 
     
    12801283            'onclick' => sprintf("return %s.command('add-contact','%s',this)", JS_OBJECT_NAME, urlencode($string)), 
    12811284            'title' => rcube_label('addtoaddressbook'), 
     1285            'class' => 'rcmaddcontact', 
    12821286          ), 
    12831287          html::img(array( 
Note: See TracChangeset for help on using the changeset viewer.