GithubHelp home page GithubHelp logo

Does this handle CSS? about dompurify HOT 16 CLOSED

cure53 avatar cure53 commented on July 24, 2024
Does this handle CSS?

from dompurify.

Comments (16)

cure53 avatar cure53 commented on July 24, 2024

In its current state: no.
We would need two things for that:

a) A CSS parser in JS that matches what browsers do individually
b) A threat model to be able to spec what it should prevent and what's legitimate

Unfortunately, there's no unified DOM API yet (afaik) that allows us to get there - or something that allows to easily and safely get all rules from a certains tylesheet and iterate over them. If there was one, we could actually consider.

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

@joelabair So, I did some research and found out that we can indeed handle CSS sanitation in a clean and cross-browser compatible way.

Now, what I would like to know before starting an implementation: What kind of sanitation would you need? How do you imagine config and purpose?

from dompurify.

graste avatar graste commented on July 24, 2024

There's a multitude of stuff I wouldn't want to allow on user provided styles. The least would be to disallow URIs and calc usages I guess. You'll probably know heaps of other properties or values that should be restricted as their usage can support certain kinds of attacks. Preferably I would want to have a whitelist of selectors and properties (plus allowed values!) instead of sanitizing things as there are so many CSS hacks out there that influence the interpretation of styles in browsers (see http://browserhacks.com/ and more).

Incomplete list of interesting things:

  • certain properties like list-style-image, background-image, border-image, content, cursor, filter and their respective shorthand notations if applicable
  • certain property values like url(), image(), calc(), "progid:…(…)" with or without whitespaces, quotes etc.
  • certain selectors so people can only affect certain parts of a page and aren't easily able to hide iframe, object or similar elements
  • allow/disallow absolute/relative URIs for url() and image() and perhaps more?
  • -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; or similar progid stuff
  • opacity: 0.01 to make transparent buttons clickable in IE ;)
  • css at rules like e.g. targeting FF via @-moz-document url-prefix() { … }, the obvious @import and whatever else there's available via such rules
  • the whole @font-face { font-family { src: … } } stuff plus unicode-range, font-feature-settings and whatnot
  • DOS relevant stuff like animations and advanced filters or new features that may not only render browsers unresponsive but may also be used to trigger crashes when there are bugs in hardware rendering support or whatever user agents do nowadays when they get creative
  • probably lots of other stuff I can't think of atm. :-)

Thanks for DOMPurify!

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

@graste Thanks! So, here's what I think is possible. Let's assume the following files:

//test.html
<link rel="stylesheet" href="test.css">
<p>blafasel</p>
/* test.css */
* {
    color: blue;
    background: red;
}

What we can do to find out about CSS property-value details is the following (very ugly code, demo only):

for(var i in styles = document.styleSheets) {
  for(var j in styles[i].cssRules) {
    for(var k in rules = styles[i].cssRules[j]) {
      if(rules[k] instanceof CSS2Properties){
        for(var l in rule = rules[k]) {
          if(isNaN(l) && rule[l] && typeof rule[l] === 'string') {
            console.log(l + ':' + rule[l])
          }
        }
      }    
    }
  }
};

So, as you can see we can go over all CSS property-values and decide if we like them or not - by whatever criteria we choose. After that we simply assemble a new style sheet and throw it into the sanitized document. Done. No risk for browser weirdness, no massive overhead.

So we don't have to parse, use regex or anything to get hands on the important data.

Now the tricky question is: What do we validate against? A white-list of properties? A conformity pattern for values? A conformity pattern for selectors? Depending on the context, different requirements might exist. And once we have them - how do we allow users to configure them?

Technically, CSS sanitation is possible in the DOM. But what API do we offer to do it?

from dompurify.

graste avatar graste commented on July 24, 2024

No fast answers here. The obvious thing would be a whitelist of properties. I'm not sure about sanitizing property values as I'm not sure if browsers skip weird values already (I'd guess so, though). Allowing only certain values for certain properties would be cool, but I'm not sure if that's worth the effort or if devs even want to configure something like that.

How about some sensible defaults or config options like this:

  • allow_external_resources (default: false) to disallow url, src, image etc. by default. For finer grained access one could support something like allow_url, allow_external_resources_on: ['cursor', 'background', 'background-image'…].
  • when allowing external resources it would be nice to allow only certain URI schemes or disallow absolute URIs altogether (use case would probably be theming with external resources from the current domain or self uploaded stuff from a specific asset subdomain) - e.g. allow_absolute_uris or allowed_uri_prefixes: ['https://assets.foo.com', 'https://flickr.com/'] - people allowing this are obviously still vulnerable to open redirects etc. and it may not be advisable to even allow such a feature… ;-)
  • allowed_at_rules: ['@font-face'] or disallow_at_rules altogether?
  • allow_calc, allow_progid etc.
  • allowed_selectors: ['.foo', '#bar > baz'…] to be very strict about what parts of a page may be usd for styling purposes.
  • selector_prefix to add to every rule with some selector like #special > area to limit the ease of defacing or abusing certain parts of a page via linked/embedded stylesheets. A simple mitigation for such a prefix to still render a page unusable would obviously be something like: .foo.foo.foo.foo.foo { position:fixed;width:100%;height:100%;top:0;left:0;pointer-events:none;z-index:999999; }, so I'm not sure if that would be worth the hassle. :-)

tl;dr: I'm really not sure. Except for disallowing calc and all usages of external resources as a sensible default.
PS: What about Data-URIs? I don't know where they can be a special problem in CSS.

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

I am tempted to think we need a new project for this - CSSPurify :)

from dompurify.

graste avatar graste commented on July 24, 2024

:-)

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

So, after having a bit of a look at how browsers use the CSSOM some new problems arose. I was hoping that upon accessing the CSSOM's properties, the user agent would normalize so a benefit of a potential CSSPurify would be not to be forced to deal with obfuscated CSS. I was wrong.

Here's an example:

<!-- test.html -->
<style>
    * {
         color: red;
         background: blue;
         border: /**/C\41lc(10px + 10px) solid green;
    }
</style>
<p>000</P>
console.log(document.styleSheets[0].cssRules[0].style.border)
  • In Firefox we get this as a result: calc(10px + 10px) solid green
    • This is what we expect. We could work with this.
  • In MSIE 11 we get this: empty string
    • NOTE: border is empty - but borderBottom is not and yields CAlc(10px + 10px) solid green. I have no words.
  • In Chrome nothing happens, no calc() in this obfuscated form

So you can see, browser implementations don't seem to be ready for a CSSPurifer yet. Alas we are talking about a very strict whitelist. Thoughts on this are very welcome ;)

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

It gets better. Chrome cannot deal with the CSS escape inside the property name.
It works with this code though (no \41): border: /**/Calc(10px + 10px) solid green;

The result of the JavaScript call? Watch closely:

calc(20px) solid green « We actually get the calculated value as a result, still wrapped by calc().

from dompurify.

fhemberger avatar fhemberger commented on July 24, 2024

I am tempted to think we need a new project for this - CSSPurify :)

Yes, please do so, we could add a hook to get this into DOMPurify later on. I'd love to keep the focus on this project. ;)

from dompurify.

graste avatar graste commented on July 24, 2024

Awesome examples with calc. I would've guessed (hoped) there are better parsers in browsers nowadays. :-)

from dompurify.

thomaspatzke avatar thomaspatzke commented on July 24, 2024

Locking down position to static would also be desirable, as restricting width and height to maximum values. These enable attackers to create overlays, which hijack clicks and redirect users to phishing pages.

from dompurify.

zcorpan avatar zcorpan commented on July 24, 2024

Please file bugs for the browser bugs you find. Thx

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

I decided to close this: DOMPurify will not support sanitizing CSS. I am however open to contribute to a CSSPurify project is anyone is interested to set one up. I believe there is a need and we have enough knowledge here to be able to do it.

from dompurify.

waterplea avatar waterplea commented on July 24, 2024

@cure53 is there any place where current state of CSS sanitation mentioned? Am I not safe by default, doing DOMPurify.sanitize() on, say <div style="some possibly malicious CSS">? Do I need to use hooks and manually remove stuff I consider malicious?

from dompurify.

cure53 avatar cure53 commented on July 24, 2024

Yes, CSS-based attacks are not part of our threat model. We prevent XSS and DOM Clobbering.

from dompurify.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.