Cenzic 232 Patent
Paid Advertising
web application security lab

Content Restrictions - A Call For Input

In talking with the browser companies there seems to be more and more interest in content restrictions. For those of you who don’t know anything about it, let me just quickly give you the overview. Three or four years ago I was trying to find a way for my company to put malicious user generated input into a sandbox but still allow it to show up on the site. The obvious answer was use an iframe to isolate it. That, unfortunately, has all sorts of user experience issues. The first one being that you cannot tell how big it needs to be so you often end up with double scroll-bars which messes up printing, and causes links inside flash movies to only change the iframe instead of the whole page. Yah, it’s ugly. So I started looking for alternatives.

The first was talking about the concept of a re-sizable iframe. There are security implications with that which may allow the parent to know the state of the child, so that was thrown out by the Mozilla team. There may be tricky ways to bring that up but some of the other usability problems are still there so it’s not really ideal anyway. So the best alternative is to create something that tells the browser, “If you trust me, trust me to tell you to not trust me.” This is based off of the short lived Netscape model that said if a site is trustworthy you lower the protections of the browser as much as possible. Content restrictions was born. I submitted the concept to Rafael Ebron, who handed it off to Gerv. It went to the WHATWG, and that’s where it’s stayed for the last 3 years or so.

The Netscape model doesn’t work if the site you trust has lots of dynamic content. So by extending it with content restrictions makes a lot of sense for a few reasons. The first reason is that it puts the onus on the websites to protect themselves. The other is that it doesn’t hurt any other usability, because it’s an opt-in situation. Pretty ideal, actually. While I was talking with Mozilla last week they asked me to put together a list of the top things I’d like to see in content restrictions. They are eager to get started on it, but can’t promise the world. They’d like to hear the top two ideas and then work from there.

How you instantiate content restrictions is still up for debate - whether it be a new header pointing to an XML file, or inline in meta tags or a new HTML tag. I’m a little indifferent, except that I think it should be accessible both to people writing dynamic pages, as well as people who simply include HTML placed there by whatever means (FTP, mail, etc…). So it should probably be a hybrid of a few of those, but that’s a different discussion.

So there are two use-cases. The first is that the site wants to simply remove anything potentially malicious, which could include something like JavaScript but exclude things like objects, for instance. The other is that a site might want anything dynamic, but doesn’t want anything embedded off-host to get injected into a page, or any automatic redirection of any sort.

One thing is certain - there are many sites that don’t want any content to be placed outside of the user’s content. The beauty of an iframe is that CSS only affects what’s in the iframe, JavaScript can’t overwrite things outside of it, doesn’t have access to the cookies etc. The first thing I can think of that would be highly valuable to lots of sites if they were able to create a resizeable psueo iframe to restrict the content to a portion of the page, which would include styles (absolute positioning) as well as JavaScript access to the page.

Other possibilities include not creating a new DOM (no iframes, frames, or the like on the page between two places on the page). Another is no automatic redirection that is not user initiated. That’s a common problem because malicious users perform redirection to other domains.

A possible valuable tool for content restrictions would be to be able to limit what sort of functionality is between two sets of tags. The first example would be turning off any HTML tags that aren’t allowed to be rendered. The second would be to limit the event handlers to a pre-defined set (or removing them entirely). I’ve seen a number of situations where this would have been handy as a last resort.

Another thing I have been toying with quite a bit lately is the concept of XMLHTTPRequest. One thing that has always surprised me is that it allows more than it’s name implies. That is, if you request something that isn’t XML it still gives access to the page. It could be up to the page’s digression if XHR has access to anything other than XML. That would limit XHR to session riding, rather than being able to read nonces or other unsavory functions used in worms.

So I’d like to get people’s feedback. Those are some of my ideas, but I’m hoping people will have even better ideas as well. Once I get the top two ideas, I’ll submit those, and we’ll rank order the next several ideas and submit them as supplemental ideas for a later day.

19 Responses to “Content Restrictions - A Call For Input”

  1. Dean Brettle Says:

    How about supporting an element capable of validating against some arbitrary schema (specified by an attribute) before it is rendered. Content which didn’t validate would either not be rendered at all or javascript hooks (e.g. onInvalidAttr, onInvalidElem) could be provided which would be able to modify the content before it is rendered.

    Advantages: Lots of flexibility given to site developers. Should be pretty easy for browser vendors to implement. Best practices/schemas for different use cases can evolve over time as new threats arise and/or new capabilities (i.e new holes…) are added to browsers. Probably more secure because it enumerates what is allowed instead of what is prohibited. Same schema can be used server-side for browsers without client-side support and/or to prescreen new content as it is submitted (instead of everytime it is rendered).

    Disadvantage: Invalid content would be rejected (or filtered) even if it didn’t actually try to do anything malicious, so the content authors would need to take responsibility for creating valid content. It is hard to prevent CSS attacks with a DOM validator while still allowing non-malicious content that the user has just copied and pasted from someplace else. The javascript hooks could probably be used to address this (i.e. cleanup all the invalid style attributes), but a separate CSS validation mechanism would make it a lot easier.

  2. Dean Brettle Says:

    More thoughts on this…

    My proposal wouldn’t support allowing a *limited* javascript environment. You could prevent all script or allow all script but it doesn’t provide a mechanism for allowing script but limiting what it can do if you allow it.

    To handle that, perhaps there could be some sort of onLoad handler from which you could populate a pristine javascript environment with the objects and prototypes which are allowed. For example, you could set window.prototype.open=undefined if you wanted to prevent popups or initialize it to something which checked the URL before opening the window if you only wanted to allow some popups. Also, to prevent the javascript from manipulating the DOM in a way not allowed by the schema, the DOM could be revalidated each time before it is redisplayed and/or the user can interact with it. Note: for performance reasons you probably wouldn’t want to revalidate after every DOM manipulation.

  3. Dean Brettle Says:

    FYI, the schemaLocation attribute might be appropriate for specifying the schema to validate the content against:

    http://www.w3.org/TR/xmlschema-0/#ref40

  4. Michael Says:

    Well, I know what I want, implementation is someone else’s problem — thank you very much ;-} Sorry, if these aren’t exactly content restrictions …

    1. Run the browser in a VM? Server code should not be able to blow through my browser and thereby own my laptop. (OK, VMs can be cracked too, but this at least makes it hard to own me just because I browsed a compromised web site)

    2. Put MITM and most phishers out of business — Client side-certificate, diffie-helman half-half key exchange, a PGP protected key store, and store the URL/Cert/IP address of all of my financial web sites in a secure file which can not be _written_ by the browser context

    3. Please stop me before I hurt myself — stop letting users override site security warnings. If my bank can’t keep their SSL up to date, don’t let me e-bank there! There is nothing I need to buy that justifies leaving the car unlocked in the parking lot.

  5. Ronald van den Heetkamp Says:

    Interestingly XHR is a pretty good and lowcost CSRF protection since it obeys the same origin policy. It’s tough, if not impossible to make remote CSRF when using strictly Asynchronous Javascript calls.

    Secondly, I think stripping the event handlers doesn’t do any good, a lot of developers use them and they are really useful. The DOM presented a real treasure for developers to create rich application. So DOM manipulation will be possible in any case, and if you have access to manipulate it, other things are possible as well.

    Virtulization should be taken seriously, and I mean “real” sandboxing also. This day, there isn’t real sandboxing for Javascript. With real I mean: javascript must not be allowed to manipulate the system’s memory for instance.

    Encryption is a tough case, it’s a pitfall in thinking it will solve security. It’s a mere aid to ensure authentication and integrity. Still if you own both sides, it renders useless for content restriction.

    Signing javascript, I do think developers should sign Javascript, this is already possible. Maybe it could be a lot more strict.

    I think there is little focus on strictness in the HTTP specification which almost everyone ignores it’s recommendations: http://www.rfc.net/rfc2616.html it clearly states what actions should be taken, and with which care.

    So I guess a ton of the problems still lies at the side of the developers since they would be the ones who would implement it.

    :)

  6. Spider Says:

    @Dean

    I like your idea about defining what javascript can and can’t do. I’ve been think along similar lines. I’d like to have something akin to digitally signed Javascript. Such that on the server side you define exactly what javascirpt can be used. Any javascript that was maliciously entered via xss, reflected or persistent won’t work because the client would recognize it as unauthorized code.

  7. HYPERFUKBOT Says:

    i’m not quite sure i understand what you’re asking 100%, but here’s an idea i just thought of:
    tags that prevent the rendering of other tags within them.

    this is not-real-html obviously
    <disallow tags=”script,img,meta”>
    user-submitted content
    </disallow>
    now, you may be wondering why potential XSS attackers can’t just say </disallow>, right? well, there’s a solution, just make a tag that says <disallow pairs=”1″> which prevents any rendering of the page whatsoever if more than one pair of these “disallow” tags are found on the page. if someone tries to overwrite that with another disallow tag with the “pairs” option, then the page also refuses to render. both these cases would pop up an alert box explaining to the user the error. to prevent dos’ing webpages disallow tags would be filtered from input. disallow tags would have additional options like <disallow script=”0″> meaning that javascript in ANY tag would be disallowed by the browser. This would have great advantages over server-side scanning because the browser KNOWS when it’s about to start running some javascript, and can’t be fooled like filters can.

  8. Michael Says:

    @Ronald

    You’re right, encryption does not solve everything. But we could use SSL much better than we do now.

    SSL is not currently able to prevent MITM because the web site can not authenticate the client. If the browser vendors had us generate a client certificate, then we could register our certificate with our bank (or other sites). Then a proper key exchange would make MITM attacks obsolete — they would always be 100% detectable by the client and the web site.

    The problem I see, is what to do when we are not using our personal systems to access the web.

    Further, if we registered the bank’s certificate on the client side, then we would make it very hard for the phishers too.

  9. Ian Hickson Says:

    The Content Restrictions stuff that was proposed through the WHATWG was far too complex — one of the most important aspects of any security feature is that it must be simple enough that authors will understand it, lest they make a mistake and introduce security issues. (Think “Oh no I don’t have to worry about escaping my user-generated input, I have Content-Restrictions enabled!” with some syntax error that makes the site one big XSS target.)

    The last work in in the WHATWG regarding this kind of stuff was discussed at:
    http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2007-May/011198.html
    I still need to look at this in more detail though. Please feel free to post suggestions to the list. They all get examined.

  10. Ronald van den Heetkamp Says:

    Yeah that is a good point Ian.

    It’s a really tough issue, cause the problem is still to determine the page’s integrity. How do you go about that one? Well, I’m still a firm believer in strictness, strict HTML and silently fail on malformed tags, XHTML yes partially. A set of rules and strictness seems to be inevitable.

    A few ideas I had:

    - only allow (remote) scripts inclusions in the head tag
    - fail to render remote scripts below the head
    - whitelist event handlers on html tags
    - create a sandbox on the body

    I haven’t got solutions, I’ve only got ideas.

    One idea sounds silly but I really thought about checking the page size first. Usually the page has a fixed size like 20KB, slight alterations could be seen as a modified page, then you could call restrictions on the page before rendering it completely. Yes, it triggers false positives but it could turn out to be useful. With useful I mean, a developer could set a XML file that defines the page size, and sets a couple of rules. Just like the Adobe crossdomain.xml

    In any case I’m glad people are working hard on this issue! :)

  11. HYPERFUKBOT Says:

    you’re right, it may provide a false sense of security if people use the restrictions wrong, but escaping incorrectly would also provide a false sense of security. There are places like myspace (which i admit are mainly idiotically horrible places, but they are an important part of our intarwebz landscape you know) which don’t have the luxury of escaping, a <disallow script=”0″< tag like i proposed would do wonders, especially because it prevents cross-site javascript vectors that haven’t even been thought of yet.

  12. Thor Larholm Says:

    I genuinely like the idea of being able to specify Content Restrictions. After all, the browser should have no problem in trusting the website when it specifically asks it to lower its privileges even further :)

    However I am a bit worried about the potential for complexity that any implementation would have to burden the developer with in its current blacklist state. I can imagine an almost endless list of the various features in a browser that should potentially be allowed restriction.

    Having a blacklist of features that you want to disable will naturally appeal to the IDS/IPS crowd who are used to configuring Snort with ten thousand different rules, but it will place an undue burden on the website developer. The only reasonable approach to a blacklist would be to rely on others for continued tweaking of the “disallow” list, which will only add to the complexity of any content restriction implementation.

    I would much rather prefer a whitelist implementation. If the website doesn’t specify any content restriction then the default settings would be used, which could be equal to whatever the browsers currently allow. If the website specifies any content restriction then the browser should only allow what has been explicitly defined. I for one won’t miss the ability to even render BMP files on my site :)

    This works great for the current P3P implementations and is much easier to test for the developer. Start with the bare minimum and add exceptions to your content restriction labels until your site works, then disregard anything else.

  13. RSnake Says:

    @Dean - that is something we wrestled with a lot. The fact that JavaScript can overload functions or re-write them caused us a lot of pain. I personally like the ability to stop that issue. I’m not sure it’s a #1 or #2 idea, but that definitely makes the list.

    @HYPERFUKBOT - the solution to that problem was to disallow the “keyword” from being entered. A simple blacklisting of </content-restrictions> (or whatever the tag is) would solve that. Although creating nested pairs could prove useful in certain circumstances.

    @Ian - I think that’s true only of some developers. Since this is an opt-in thing and because it would only work in certain browsers, the primary consumer would be people who already have tried to solve this method through other means but have been unable to given the technology availible. Blacklisting and whitelisting doesn’t work because consumers demand rich content and that rich content is malicious. What you’re missing is why I originally came up with this concept, and that was years ago and in a company context where the problem was well understood but there was nothing we could do about it - save hurt our own customers. It’s not laziness - at some point we need to come up with other solutions, even if they are only mitigating factors that aren’t supported in all browsers (HTTPOnly is a great example).

    @Thor - some developers don’t have a problem specifiying blacklists, but I do like the concept of whitelists as an additional measure. Really, there are a few use cases that we should consider. The first is that the site needs to render everything as if it were in a safe iframe, meaning that it is essentially an embedded iframe where no content can modify anything outside of it (or overlay on top of it, or modify styles outside of it, etc…), yet it is re-sizable to the right size and shape that it would have as if it were on the same page (unlike an iframe). The second is that the developer (like you) wants nothing on the site that’s dynamic whatsoever. Very different use cases, but both are equally important.

    In the first use case, there’s actually two sub use cases. The first one is that the site wants to allow everything, and the second (and undoubtedly more popular problem) is that the site wants to allow only a sub-set of things. That subset could be something like script but not remote script or something as complex as no redirection of any sort that is not user generated or whatever. Therein lies the major debate in my mind.

    Btw, nice job on the recent findings on your site! I was wondering when you’d come out and start posting again. You’re always welcome here.

  14. Dean Brettle Says:

    @RSnake -

    Here’s a more specific proposal aimed at your “allow only a sub-set of things” use case and an additional use case. The additional use case is where the site wants to allow the untrusted script to make modifications to some parts of the containing document or display some content that will appear over some portion of the containing document. For example, the site might want to allow an untrusted script to add a toolbar or menu item to the page.

    Anyway, here’s the proposal…

    The idea is that if we could delete (or proxy) all of the script-accessible objects before the untrusted script runs, we can prevent the script from doing any damage, or arbitrarily limit what it can do.

    So, before the untrusted script we would run a script which does the following:

    1. Create filtering proxy objects for all the script-accessible objects we want to let the untrusted script to access. By “script-accessible” objects, I mean members of the current window object, script-defined global objects, and hosted/built-in objects. We would only create filtering proxy object for some of them.
    2. Save all the script-accessible objects in a private member object that is accessible only with a server-specified nonce. The object holding this private member would need to be made undeletable somehow because we can’t allow the untrusted script to delete it.
    3. Delete all the script-accessible objects, replacing them with proxy objects as desired.
    4. Set the maximum amount of time a script is allowed to run to prevent DoS attacks. If the time is exceeded, the script is terminated but other scripts are still run.

    Then we’d run the untrusted script in this new restricted environment.

    Then to restore the original environment we’d:

    1. Delete all the proxy objects.
    2. Get all the original script-accessible objects from the private member variable, by using the nonce that only the server knows.
    3. Put all the original script-accessible objects back.
    4. Remove the time limit (or restore it to its default).

    To make such an approach work you’d need the following facilities not currently provided by Javascript:

    1. A way to list all of the global objects, including hosted objects.
    2. A way to delete any global object (even a hosted one) from the global namespace and a way to delete any property from any object (most importantly the window object). This is currently not allowed for some objects, though it isn’t clear to me why that is so.
    3. A way to define getters and setters for fields (so they could be proxied appropriately). Mozilla already supports this.
    4. A way to set the deletabilty of an object and the max script run time. These would be provided via global functions (e.g. setDeletability(obj, flag) and setMaxRunTime(secs)), so that they could be removed/proxied like any other globals to prevent the untrusted script from abusing them. Note: Firefox already limits script run time but I don’t think there is a way to control the limit from script.

    It seems like those things wouldn’t be that hard to implement. The hard part would be writing secure filtering proxy objects. That would be left to the security community. :)

    Different products could be built on this infrastructure for different use cases and application frameworks. Site developers would choose the product that fits their needs. In addition to using the technique I’ve described, a good product would also:

    1. Do server-side validation of the untrusted content to ensure that it couldn’t be used to attack the HTML parser.
    2. Set the time limit appropriately based on the number of scripts in the content.
    3. Modify untrusted attributes that can contain script (e.g. onevent, style, href) to use the above technique to run the scripts in a restricted environment.
    4. Rename “script” elements to “untrusted-script” elements on the server-side and use client script to find and run them in the restricted environment only if it is possible to create such an environment. This prevents the untrusted scripts from running in current generation browsers where it isn’t possible to create the restricted environment.

    Final thoughts…

    IMO, the primary downside to this proposal is the potential complexity of the filtering proxies and the likelihood of holes in their implementation. However, there are 2 mitigating factors.

    First, the complexity of the filtering proxies really depends on the use case. As an extreme example, if the use case is to just allow an untrusted script to add a menu item, the site would only provide one global function, addMenuItem(), and that would be pretty easy to write securely. On the other end of the spectrum is the use cases where the site wants to allow the script to do “anything a trusted script could do except for a few things”. That requires a complex (and more likely insecure) implementation. The question is where to put that complexity. Which leads to the second mitigating factor.

    This proposal puts the complexity in javascript. The alternative is to put the complexity into the browsers. By requiring less changes to the browser, this proposal should be easier for browser vendors to adopt quickly. It should also reduce the chances of introducing new holes in the browsers. Moreover, if the complexity is going to increase the number of bugs, sites would rather fix their javascript than wait for browser vendors to release updates and then wait for all users to update.

    Sorry for the length…

  15. kaes Says:

    how about something (maybe a certain kind of doctype?) that causes the browser to *only* execute Javascript that is included via a [SCRIPT SRC= tag in the [HEAD] section of your HTML document.
    so, no onclick or onmouseover attributes specified in the HTML anywhere. according to proper web application design principles there should be separation of content/layout AND behaviour, and linking an external .js file in the [HEAD] section is the only proper way to do this (event handlers can and should be attached via DOM-functions, as explained on www.quirksmode.org)
    then, the problem to prevent XSS would become a problem to keep user-input entirely outside the [HEAD] section, which shouldn’t be too big of a problem, and if your application somehow requires that anyway, you should probably rethink your design :)

  16. HYPERFUKBOT Says:

    some more ideas for here:
    - A <sandbox> tag that makes javascript/vbscript unable to reach outside of the tag. The sandbox tag would work as if from another domain in the same-domain policy. The tag would have an id attribute such as: <sandbox id=”q”>. If placed on ha.ckers.org, then the javascript within the tag would run from the “ha.ckers.org\q” domain. Javascript on the ha.ckers.org domain WOULD be able to access ha.ckers.org\q information, but not the other way around.
    - With the <disallow> that i talked about earlier that RSnake referred to as <content-restrictions> tags (which is a much better name, thank you), I had an additional idea. An id attribute that has a cryptographic nonce / sessionid that prevents injected HTML from closing the tag. <content-restrictions id=”141234asdf328098erer907r80re26″> would only be closeable by </content-restrictions id=”141234asdf328098erer907r80re26″>. Without javascript, you can’t get the nonce, without closing the tag you can’t get javascript. This is a much better solution than the ‘pairs’ method that I thought of earlier.

  17. Wladimir Palant Says:

    Sorry, I am late to the party. RSnake, I only wanted to mention that XMLHttpRequest isn’t the only way to read any text file in your domain. You can simply load the text into an iframe and read it out once it finished loading. No real difference, XMLHttpRequest is only more comfortable. Should text frames also be restricted to XML files? How about images, scripts?

  18. RSnake Says:

    @Dean - unfortunately I think from a speed perspective you must do it inline, you can’t wait for all the scripts to load before performing the security function.

    @kaes - I think that’s a great idea, assuming you cannot specify two head elements, or somehow write into the head element (EG: </title>exploit goes here).

    @HYPERFUKBOT - you’re right on in the nonces. If they don’t know the nonce ahead of time there’s no way to execute them. Browsers will naturally ignore the erronenous tag which helps with backwards compatibility. That’s the route I think makes the most sense when specifying inline elements.

    @Wladimir - that is true, however as Billy Hoffman pointed out when he improved pdp’s code, the advantage to using AJAX in a worm over iframes is that it’s also much faster. You aren’t loading up all the images, CSS, JavaScript, etc… that goes along with grabbing the nonce or whatever.

    Also, you can’t specify the method in an iframe (granted you can still do that in other was by building form boxes, etc). Minor differences, but I think they are enough that that’s why people have gravitated towards XHR as a worm writer’s tool of choice. But your point is well taken, I should have mentioned that.

  19. Sriram Krishnan Says:

    There is an interesting paper from MSR on this topic. It relies on browser modifications and can be said to be similar to the sandbox tag idea above

    http://research.microsoft.com/~helenw/papers/sosp07MashupOS.pdf