21

I want to allow users to use their own stylesheets for thei profiles on my forum, but I'm afraid of possible security vulnerabilities. Does anyone have any tips for sanitizing CSS?

Basic process: User enters CSS into form -> Save to DB -> Output as inline CSS

Gio Borje
  • 20,314
  • 7
  • 36
  • 50
  • 1
    With the exception of the non-standard `behavior` property and `expressions` that IE allows (both of which initiate javascript), I don't see how css could cause any "security vulnerabilities." So if you filter out (or disallow input of) those, I think you would be okay. – ScottS Jul 13 '10 at 21:27
  • 7
    moz-bindings. `javascript:` URLs in everything that accepts `url()`. Layout hacks to position other content over the top of a login form, `@import` to bring in an unchecked external file that the author might sabotage later. CSS isn't really that safe. – bobince Jul 13 '10 at 21:52
  • Thanks bobince, I was not aware of some of those dangers. – ScottS Jul 14 '10 at 10:26
  • 1
    From http://www.sk89q.com/2009/08/definitive-php-security-checklist/ * Be aware that certain CSS properties such as “position” could be used maliciously (elements overlaying login forms, etcetera). * CSS can also contain escape sequences both inside and outside strings (\34). * CSS files can contain JavaScript. This manifests itself in the form of “CSS expressions” and “behaviors” (Internet Explorer features) or Gecko “bindings.” – fire Jul 14 '10 at 16:31
  • is your issue was resolved? – Tech Kid Oct 06 '18 at 13:20
  • Can you pls look into my issue: https://stackoverflow.com/questions/52677988/sanitise-css-with-csstidy-with-custom-filter – Tech Kid Oct 06 '18 at 13:20

4 Answers4

22

HTMLPurifier with CSSTidy does what you're looking for.

HTMLPurifier is primarily designed for sanitizing HTML, but also has an option to extract style blocks with CSSTidy.

There's an example in the HTMLPurifier docs (but alas, I've used up my two links per post.)

Here's another:

require_once './htmlpurifier/library/HTMLPurifier.auto.php';
require_once './csstidy/class.csstidy.php';

// define some css
$input_css = "
    body {
        margin: 0px;
        padding: 0px;
        /* JS injection */
        background-image: url(javascript:alert('Injected'));
    }
    a {
        color: #ccc;
        text-decoration: none;
        /* dangerous proprietary IE attribute */
        behavior:url(hilite.htc);
        /* dangerous proprietary FF attribute */
        -moz-binding: url('http://virus.com/htmlBindings.xml');
    }
    .banner {
        /* absolute position can be used for phishing */
        position: absolute;
        top: 0px;
        left: 0px;
    }
";

// Create a new configuration object
$config = HTMLPurifier_Config::createDefault();
$config->set('Filter.ExtractStyleBlocks', TRUE);

// Create a new purifier instance
$purifier = new HTMLPurifier($config);

// Turn off strict warnings (CSSTidy throws some warnings on PHP 5.2+)
$level = error_reporting(E_ALL & ~E_STRICT);

// Wrap our CSS in style tags and pass to purifier. 
// we're not actually interested in the html response though
$html = $purifier->purify('<style>'.$input_css.'</style>');

// Revert error reporting
error_reporting($level);

// The "style" blocks are stored seperately
$output_css = $purifier->context->get('StyleBlocks');

// Get the first style block
echo $output_css[0];

And the output is:

body {
    margin:0;
    padding:0;
}

a {
    color:#ccc;
    text-decoration:none;
}

.banner {
}
dleavitt
  • 1,386
  • 13
  • 14
  • Thanks; hopefully no one on my site was hit by a CSRF with my meager RegEx replacements. – Gio Borje Mar 06 '11 at 19:34
  • This is a fantastic answer that greatly helped me with something I'm doing. Thanks a lot. – John Apr 21 '11 at 10:40
  • this works great! Just one stumbling block: how to configure CSS tidy in the context of HTMLpurifier, with PHP runtime code like shown above? Same question (essentially) as is here: http://stackoverflow.com/questions/10843600/is-there-a-way-to-stop-htmlpurifier-csstidy-from-forcing-input-css-into-all-lowe/ – govinda Jun 01 '12 at 04:27
  • any way to achieve this without using HTMLPurifier with CSSTidy – kta Jun 16 '16 at 06:46
  • Can someone pls help me with my question: https://stackoverflow.com/questions/52677988/sanitise-css-with-csstidy-with-custom-filter – Tech Kid Oct 06 '18 at 13:19
2

Define the classes yourself, and make a GUI to apply color and other properties to each class, use the same approach twitter does for that.

alt text http://grab.by/grabs/3217158e9c48538eb127fb1678dab6ae.png

Of course, this would only work if your layout is fixed and defined by the admin, not the user.

Germán Rodríguez
  • 4,284
  • 1
  • 19
  • 19
  • I was hoping to give users a little more flexibility by using a blacklist instead of a whitelist. – Gio Borje Jul 13 '10 at 21:52
  • 3
    Blacklists need constantly updating as browsers add new features and bugs in browsers allow things to slip through the cracks. Whitelists are the only sane approach for filtering data for security issues. – Quentin Mar 06 '11 at 11:40
  • Image link is broken. – MattCochrane Jun 22 '20 at 03:01
0

I don't see how this could possibly create security vulnerabilities, unless the profiles are shared with other users.

If they're shared, CSRF vulnerabilities could come up (since CSS can generate GET requests to include images, fonts, other stylesheets etc). They could also use content to trick users into clicking some places, hide important functionality, etc. And, of course, you would have to escape <, >, and possibly & to prevent XSS (if the CSS is embedded in the HTML).

As to libraries to do the sanitation, I'm not aware of any (maybe tidy).

Artefacto
  • 96,375
  • 17
  • 202
  • 225
0

This probably won't fix all sorts of hacks but probably most automated hacks at least:

$css = strip_tags($css);
$css = htmlspecialchars($css, ENT_HTML5 | ENT_NOQUOTES | ENT_SUBSTITUTE, 'utf-8');

Depends on how many users are allowed to use this feature and how big of a threat it could be due to that..

OZZIE
  • 6,609
  • 7
  • 55
  • 59