Paid Advertising
web application security lab

CSS Security

There is an interesting blog post over at discussing how to sanitize CSS for the purpose of making it acceptable for blog submissions to avoid cross site scripting. This is an interesting problem I’ve spent weeks on end thinking about last year. Is it possible? Yes, with caveats. Keeping a web application safe from CSS by still allowing it is almost as hard as keeping it safe from JavaScript but still allowing it. You have to make some clear distinctions about what Cascading Style Sheets can do and what you need to be able to stop from happening.

There are four things CSS can do that I think fall into different application security severity buckets but also, in my opinion the severity is inversely proportionalte to the complexity of the fix.

  1. CSS can instantiate JavaScript/VBScript (which can lead to XSS)
  2. CSS can pull remote images (which can lead to CSRF)
  3. CSS can overlay tags at any location (which can lead to inadvertant behavior like clicking on tags that you think take you to a login page but really take you to another site)
  4. CSS can alter the colors, borders, cursor, scrollbars, etc… (which can hurt your branding)

So it really depends on what you are trying to stop. If you are simply trying to stop XSS, even that can be a nightmare. Firstly, you have to keep the content on the page, so the @import function and link tags must be rejected. Next, you need to sanitize the information by removing erroneous characters and comments, blah blah before detection. Then you need to search for injection points, like expression and url and reject those. Also, make sure you have made your page in a character encoding like UTF-8 so you don’t run into UTF-7 or US-ASCII issues. Are you then safe? Honestly, I don’t know. As CSS evolves, the chances of that being the only way to instantiate JavaScript and VBScript are pretty low. Just when I think I know all the tricky ways to get JavaScript on a page I find out one more that blows everything we knew out of the water. But for now it may work.

To stop CSRF you are have the same rules as above, but now you need to remove any function that can include a remote image. Fortunately, this also happens to work the same way as above. Because if you can include a remote image, you can include a JavaScript directive, so you may actually be okay if you remove the XSS above. No promises though, CSS is not finished adding features.

To stop overlays, you need to reject positioning tags. That can be a mess, but I believe it’s possible. Both absolute and relative positioning are risky. There maybe ways to wrap the information in tags to reduce the risk of positioning tags. See the comments in this old post where Dean Brettle and I discuss CSS wrapping for some ideas.

Lastly, to remove the rest of the branding issues, one trick is to throw the content in an iframe so it does not have access to outside the frame in question. Outside of that, wrapping may work for some things, but definitely not changing the scrollbars or something equally annoying.

Frankly, I’m not sure CSS has a place in user input mixed with your content unless you resign the page to being at least partially under the stylistic control of the user.

2 Responses to “CSS Security”

  1. yawnmoth Says:

    You refer to “expression and url” as injection points that would need to be blocked to protect against XSS, but then say that remote images would have to be blocked, as well, to protect against CSRF. Wouldn’t blocking url prevent remote images? Or can remote images be referenced in CSS without url?

  2. RSnake Says:

    Yah, that’s actually what I said (maybe it wasn’t super clear). “Fortunately, this also happens to work the same way as above. Because if you can include a remote image, you can include a JavaScript directive, so you may actually be okay if you remove the XSS above.”

    Meaning if you remove url and expression you have removed the two ways I am aware of to include a remote document (excluding things like @import and link tags prior to that, of course). So to answer your question, yes, but don’t hold me to it. There may be other ways that I am not aware of, as CSS is pretty feature rich and evolves with every browser iteration.