Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Inline JS/CSS vs Content Security Policy (bug 948151)

55 views
Skip to first unread message

Les Orchard

unread,
Jan 15, 2014, 10:42:31 AM1/15/14
to dev...@lists.mozilla.org
We've done a handful of performance tweaks lately to save on HTTP requests that increase the amount of JavaScript & CSS we serve up inline with our HTML.

However, we also have bug 948151 [1] requesting that we use Content Security Policy on MDN. CSP disallows inline CSS & JavaScript by default. You can explicitly enable it, but it's very much discouraged.

So, a performance strategy conflicts with a security strategy.

This is something we need to sort out - ie. will we ever support CSP? If so, we need to back away from pushing more things into the HTML. Otherwise, we'll need to undo - or at least redo - a lot of work to make CSP happy

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=948151

--
Les Orchard <lorc...@mozilla.com>
{web,mad,computer} scientist

Jean-Yves Perrier

unread,
Jan 15, 2014, 11:05:42 AM1/15/14
to dev...@lists.mozilla.org
Not sure if it is relevant here or not, but we still have plenty of
style=".." scattered all around our doc. I try to kill them little by
little but it is still a long-term work.
"Prenez soin des minutes, les heures prendront soin d'elles-m�mes."
P.D. Stanhope (4e baron de Chesterfield, 1694-1773)

David Bruant

unread,
Jan 15, 2014, 11:16:49 AM1/15/14
to Les Orchard, dev...@lists.mozilla.org
Le 15/01/2014 16:42, Les Orchard a �crit :
> We've done a handful of performance tweaks lately to save on HTTP requests that increase the amount of JavaScript & CSS we serve up inline with our HTML.
>
> However, we also have bug 948151 [1] requesting that we use Content Security Policy on MDN. CSP disallows inline CSS & JavaScript by default. You can explicitly enable it, but it's very much discouraged.
As far as background, it is discouraged because if MDN gets XSS'ed, the
attacker could leave an inline JS snippet which is executed no matter
what by the browser.
Note that with a proper CSP policy, an inline script can't leak data
(via classic means like x-origin <img> or XHR). It still can force the
user to leave MDN to a malicious clone or some other form of phishing,
but that's quite some work.

> So, a performance strategy conflicts with a security strategy.
Sad when it comes to this :-(
CSP 1.1 introduces the notion of nonce to work around this problem. I
think it's still being discussed and implemented nowhere (but something
to keep an eye on).
The idea is that an inline <script> has a @nonce attribute and it will
be executed only if the nonce is part of the CSP directive (with some
CSP directive syntax, whatever).
An attacker can only have its inline script executed if it can get to
know the nonce (which is impossible enough if the nonce is randomly
generated).

I believe you can implement this nonce thing yourself following these steps:
1) use unsafe-eval in the CSP directive (I believe disabling eval is a
stupid idea anyway, because there is no risk inherent to eval, only bad
usages)
2) Add a server-generated self-removing <script> encapsulating the
nonces that will be used for inline scripts (self-removing so no one can
access its .textContent... though I'm not sure that it could be harmful)
3) Add @data-nonce to the trusted inline scripts with the nonce values
4) After the HTML is loaded (including the inline scripts which didn't
run), do a document.querySelector to find the trusted inline scripts,
get their textContent and eval that.

This technique does not work if you depend on inline script features
like document.readyState (usually "loading" in inline scripts) or
document.write (in which case, I'll contribute right away to get rid of
these ;-) ), etc.

If I was too abstract, I can do a stand-alone prototype maybe Friday,
maybe next week?

> This is something we need to sort out - ie. will we ever support CSP?
Given how high-profile MDN is, it would be recommended to support CSP no
matter what. The policy can be refined over time.
IMHO, the question shouldn't be "will we support CSP?" (because the
answer should always be yes), but "which policy specifically?"
For instance, you can ship CSP right now with unsafe-inline and create a
second bug to remove it.

To bypass CSP, do data URIs work in script@src?

David

David Walsh

unread,
Jan 15, 2014, 11:25:54 AM1/15/14
to David Bruant, Les Orchard, dev...@lists.mozilla.org
There are a few templates which have inline JS which simply move to a
.js resource, FWIW.

David
> _______________________________________________
> dev-mdn mailing list
> dev...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-mdn

Gervase Markham

unread,
Jan 16, 2014, 7:03:40 AM1/16/14
to Les Orchard
On 15/01/14 15:42, Les Orchard wrote:
> We've done a handful of performance tweaks lately to save on HTTP
> requests that increase the amount of JavaScript & CSS we serve up
> inline with our HTML.
>
> However, we also have bug 948151 [1] requesting that we use Content
> Security Policy on MDN. CSP disallows inline CSS & JavaScript by
> default. You can explicitly enable it, but it's very much
> discouraged.
>
> So, a performance strategy conflicts with a security strategy.

Can we put all the JS into a concatenated JS file, and same for the CSS?
That's not a problem for CSP.

That means two loads per page, but it doesn't have to be more than two.

Gerv

Luke Crouch

unread,
Jan 17, 2014, 2:16:09 AM1/17/14
to Gervase Markham, dev...@lists.mozilla.org
We concatenate and compress JS and CSS files via jingo-minify. [1]

But, we also dynamically generate other JS and CSS resources including
some database-derived values. jingo-minify has no ability to include
these resources.

So, we started moving the dynamic JS & CSS into inline content to save
the extra HTTP requests - especially HTTP requests to the slow back-end
server.

Which means we can't simply put both kinds of JS and CSS together into
single files - it would be a very non-trivial task. :/

-L

[1] https://github.com/jsocol/jingo-minify/

--
Q: Why is this email five sentences or less?
A: http://five.sentenc.es

Daniel Veditz

unread,
Jan 21, 2014, 5:26:21 PM1/21/14
to
On 1/15/2014 8:16 AM, David Bruant wrote:
> To bypass CSP, do data URIs work in script@src?

data: URIs can be made to work, but they are normally blocked and have
to be explicitly whitelisted in the CSP policy. Whitelisting data: in
the script-src policy is effectively allowing inline scripts, but it can
be useful to allow data: for img-src or similar passive types.

-Dan Veditz

grob...@mozilla.com

unread,
Jan 21, 2014, 6:09:50 PM1/21/14
to
On Wednesday, January 15, 2014 8:16:49 AM UTC-8, David Bruant wrote:
> Le 15/01/2014 16:42, Les Orchard a �crit :
>
> > We've done a handful of performance tweaks lately to save on HTTP requests that increase the amount of JavaScript & CSS we serve up inline with our HTML.
>
> >
>
> > However, we also have bug 948151 [1] requesting that we use Content Security Policy on MDN. CSP disallows inline CSS & JavaScript by default. You can explicitly enable it, but it's very much discouraged.
>
> As far as background, it is discouraged because if MDN gets XSS'ed, the
>
> attacker could leave an inline JS snippet which is executed no matter
>
> what by the browser.
>
> Note that with a proper CSP policy, an inline script can't leak data
>
> (via classic means like x-origin <img> or XHR). It still can force the
>
> user to leave MDN to a malicious clone or some other form of phishing,
>
> but that's quite some work.

That's a good point. There are security benefits to using a policy with 'unsafe-inline', although the benefits are much greater without it.

>
>
> > So, a performance strategy conflicts with a security strategy.
>
> Sad when it comes to this :-(
>
> CSP 1.1 introduces the notion of nonce to work around this problem. I
>
> think it's still being discussed and implemented nowhere (but something
>
> to keep an eye on).

It's actually implemented in both Firefox and Chrome, but it's behind a pref in both (security.csp.experimentalEnabled in FF). It's part of the CSP 1.1 spec, which is still in progress (although nearing completion). We will probably want to wait until the spec is finalized before flipping/removing that pref.

>
> The idea is that an inline <script> has a @nonce attribute and it will
>
> be executed only if the nonce is part of the CSP directive (with some
>
> CSP directive syntax, whatever).
>
> An attacker can only have its inline script executed if it can get to
>
> know the nonce (which is impossible enough if the nonce is randomly
>
> generated).
>
>
>
> I believe you can implement this nonce thing yourself following these steps:
>
> 1) use unsafe-eval in the CSP directive (I believe disabling eval is a
>
> stupid idea anyway, because there is no risk inherent to eval, only bad
>
> usages)
>
> 2) Add a server-generated self-removing <script> encapsulating the
>
> nonces that will be used for inline scripts (self-removing so no one can
>
> access its .textContent... though I'm not sure that it could be harmful)
>
> 3) Add @data-nonce to the trusted inline scripts with the nonce values
>
> 4) After the HTML is loaded (including the inline scripts which didn't
>
> run), do a document.querySelector to find the trusted inline scripts,
>
> get their textContent and eval that.
>
>
>
> This technique does not work if you depend on inline script features
>
> like document.readyState (usually "loading" in inline scripts) or
>
> document.write (in which case, I'll contribute right away to get rid of
>
> these ;-) ), etc.

That's an interesting and clever idea! However, I think we can do this with less effort. And I would not say blocking eval is pointless. How easy is it to be sure that attacker-controlled content is never eval'ed?

> > This is something we need to sort out - ie. will we ever support CSP?
>
> Given how high-profile MDN is, it would be recommended to support CSP no
>
> matter what. The policy can be refined over time.
>
> IMHO, the question shouldn't be "will we support CSP?" (because the
>
> answer should always be yes), but "which policy specifically?"
>
> For instance, you can ship CSP right now with unsafe-inline and create a
>
> second bug to remove it.

This is a good plan, and very similar to what Facebook is doing, because they also use heavily use inline scripts for performance reasons.

>
>
> To bypass CSP, do data URIs work in script@src?

I don't understand your meaning. Are you asking if data-uris can be used as a CSP bypass? (no)

>
>
> David

David Bruant

unread,
Jan 21, 2014, 6:51:40 PM1/21/14
to grob...@mozilla.com, dev...@lists.mozilla.org
Le 22/01/2014 00:09, grob...@mozilla.com a �crit :
>> The idea is that an inline <script> has a @nonce attribute and it will
>>
>> be executed only if the nonce is part of the CSP directive (with some
>>
>> CSP directive syntax, whatever).
>>
>> An attacker can only have its inline script executed if it can get to
>>
>> know the nonce (which is impossible enough if the nonce is randomly
>>
>> generated).
>>
>>
>>
>> I believe you can implement this nonce thing yourself following these steps:
>>
>> 1) use unsafe-eval in the CSP directive (I believe disabling eval is a
>>
>> stupid idea anyway, because there is no risk inherent to eval, only bad
>>
>> usages)
>>
>> 2) Add a server-generated self-removing <script> encapsulating the
>>
>> nonces that will be used for inline scripts (self-removing so no one can
>>
>> access its .textContent... though I'm not sure that it could be harmful)
>>
>> 3) Add @data-nonce to the trusted inline scripts with the nonce values
>>
>> 4) After the HTML is loaded (including the inline scripts which didn't
>>
>> run), do a document.querySelector to find the trusted inline scripts,
>>
>> get their textContent and eval that.
>>
>>
>>
>> This technique does not work if you depend on inline script features
>>
>> like document.readyState (usually "loading" in inline scripts) or
>>
>> document.write (in which case, I'll contribute right away to get rid of
>>
>> these ;-) ), etc.
> That's an interesting and clever idea! However, I think we can do this with less effort.
Assuming nonce, I agree, but it's not deployed yet and will suffer from
deployed browsers supporting CSP-without-nonce. Even when enabled in
Chrome and Firefox, nonce will be impractical for ~3 years because of
IE10/11.
We can benefit from parts of CSP today without it. Preventing attackers
to reach back to malicious servers is already a major win in my opinion.

default: *.mozilla.com *.mozilla.org
can go a long long way

> And I would not say blocking eval is pointless. How easy is it to be sure that attacker-controlled content is never eval'ed?
very easy?
If the people writing the JS are noobs, they may use eval with string
concatenation or a string as first argument of setTimeout, but I trust
the Kuma devs to not do that even if tired and/or lacking coffee.
The remaining use cases for eval/new Function are lodash-style function
templates for the sake of performance and the content being eval'ed is
tighlty controlled.
I understand why Chrome extensions default to not allowing eval, but I
believe Kuma devs are expert enough in JS.
In case they doubt themselves, it's easy enough to have automated
tooling raising a flag [1][2] in case something fishy is happening with
eval, but I don't even think it's necessary.

> To bypass CSP, do data URIs work in script@src?
> I don't understand your meaning. Are you asking if data-uris can be used as a CSP bypass? (no)
Yeah, as Daniel said, it works only if data urls are allowed by the CSP
policy.

David

[1] https://github.com/eslint/eslint/blob/master/lib/rules/no-eval.js
[2] I wanted to link to
http://typescript.codeplex.com/sourcecontrol/latest#typings/lib.d.ts but
they consider the type of setTimeout first argument as any. It's
overridable anyway.
0 new messages