1 (edited by virtual 2008-08-10 06:35:07)

Topic: Denying CSS properties in style attribute

I have come over from HtmlPurifier, but I will continue to use it until 1 little problem can be done with HtmLawed. It might already be able to, but I couldn't locate it in the documentation:

Can we filter CSS attributes in the style attribute? Imagine something like this:

<div style="position:absolute;width:100%;height:100%;background:#FFF">
    <a href="http://evil.org/dangerous.html">We have moved sites, click here to continue!</a>
</div>

I would want to filter out the 'position' CSS attribute - possible?
Thanks :-)

Edit: We want the style attribute to be allowed, which is why we would want the ability to filter css attributes.

2

Re: Denying CSS properties in style attribute

There are a few ways to achieve the functionality.

1. Disallow 'style'

Permit 'class' instead, define the CSS properties for classes in your style-sheet, and let the authors know the class-names they can use. But I guess this is not what you want to implement, though this option is the fastest and the most 'secure'.

2. Use '$spec'

I guess you don't want this either, but a '$spec' value like this can be used to remove 'style' completely if the attribute's value has, e.g., 'position' in it:

div=style(nomatch=#position:#i)

3. Use 'hook_tag'

The 'hook_tag' 'config' parameter is probably what you want to use, with the parameter declared as the name of your custom function.

$config = array('hook_tag' => 'my_css_filter');
$out = htmLawed($in, $config);

Below is an example of the declared function which needs to be available to your script:

function my_css_filter($element, $attribute_array){
 // Inline style value check
 if(isset($attribute_array['style'])){
  // Check/filter CSS property-value pairs
  $css = explode(';', $attribute_array['style']);
  $style = array();

  foreach($css as $v){

   if(($p = strpos($v, ':')) > 1 && $p < strlen($v)){

    $css_property_name = trim(substr($v, 0, $p));
    $css_property_value = trim(substr($v, $p+1));

    // Property-specific checks

    // 'position' not allowed for 'div'
    if($element == 'div' && $css_property_name == 'position'){
     continue;
    }

    // And more checks
    // ...
    // End checks

    $style[] = "$css_property_name: $css_property_value";

   }

  }
  
  // Rebuild inline style value
  if(!empty($style)){
   $attribute_array['style'] = implode('; ', $style);
  }
  else{
   unset($attribute_array['style']);
  }
 }
 
 // Build the element attributes string
 $attributes = '';
 foreach($attribute_array as $k=>$v){
  $attributes .= " {$k}=\"{$v}\"";
 }
 
 // Return the opening tag with attributes
 static $empty_elements = array('area'=>1, 'br'=>1, 'col'=>1, 'embed'=>1, 'hr'=>1, 
  'img'=>1, 'input'=>1, 'isindex'=>1, 'param'=>1);
 return "<{$element}{$attributes}". (isset($empty_elements[$element]) ? ' /' : ''). '>';
}

Note that you can completely disallow 'style' for some elements, finely check the CSS property values, force default values, and so on, using such functions. The drawback is this requires the ability to code in PHP.

3

Re: Denying CSS properties in style attribute

Thanks, worked great. :-)

4

Re: Denying CSS properties in style attribute

As of the new, 1.1.11, version of htmLawed, when a 'hook_tag' function has been declared, closing tag contents (and not just opening tag contents) are also passed to the function. If upgrading htmLawed, one may need to edit the 'hook_tag' function. See http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawed_README.htm#s4.5.