Skip to content

Commit

Permalink
[css-variables-1] Specify a required defense against the "billion lau…
Browse files Browse the repository at this point in the history
…ghs" attack. Fixes #3733
  • Loading branch information
tabatkins committed Mar 15, 2019
1 parent bf6a156 commit 5e36a2e
Showing 1 changed file with 50 additions and 1 deletion.
51 changes: 50 additions & 1 deletion css-variables-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,51 @@ Variables in Shorthand Properties</h3>
if any of the longhand subproperties for that shorthand have <a>pending-substitution values</a>
then the serialized value of the shorthand must be the empty string.

<h3 id=long-variables>
Safely Handling Overly-Long Variables</h3>

Naively implemented,
''var()'' functions can be used in a variation of the "billion laughs attack":

<div class=example>
<pre lang=css>
.foo {
--prop1: lol;
--prop2: var(--prop1) var(--prop1);
--prop3: var(--prop2) var(--prop2);
--prop4: var(--prop3) var(--prop3);
/* etc */
}
</pre>

In this short example, ''--prop4''’s computed value is ''lol lol lol lol lol lol lol lol'',
containing 8 copies of the original ''lol''.
Every additional level added to this doubles the number of identifiers;
extending it to a mere 30 levels,
the work of a few minutes by hand,
would make ''--prop30'' contain <em>nearly a billion instances</em> of the identifier.
</div>

To avoid this sort of attack,
UAs must impose a UA-defined limit on the allowed length of the token stream

This comment has been minimized.

Copy link
@emilio

emilio Mar 15, 2019

Collaborator

You sure you want to make this a "must"? @andruud was considering not adding one to chrome.

This comment has been minimized.

Copy link
@andruud

andruud Mar 15, 2019

Member

Don't worry, I'll add one. 🙂

This comment has been minimized.

Copy link
@tabatkins

tabatkins Mar 15, 2019

Author Member

"must" is appropriate whenever there's no good reason not to do the thing. This is definitely such a case. ^_^

(When I was writing that sentence, I definitely hesitated for several seconds to weigh my 2119 options. MUST was a deliberate choice.)

This comment has been minimized.

Copy link
@AmeliaBR

AmeliaBR Mar 15, 2019

Contributor

"must" have a limit, when we don't specify what that limit is, basically compiles down to "must not crash because of this", which seems perfectly reasonable. Because there's always a limit, it's just a case of whether it's enforced by your code or by the device!

This comment has been minimized.

Copy link
@tabatkins

tabatkins Mar 15, 2019

Author Member

And that's exactly what the WPT test exercises; you fail if you crash/timeout on expanding out 10^20 "lol" idents, succeed otherwise. ^_^

that a ''var()'' function expands into.
If a ''var()'' would expand into a longer token stream than this limit,
it instead makes the property it's expanding into
[=invalid at computed-value time=].

This specification does not define what size limit should be imposed.
However, since there are valid use-cases for custom properties that contain a kilobyte or more of text,
it's recommended that the limit be set relatively high.

Note: The general principle that UAs are allowed to violate standards due to resource constraints
is still generally true here;
a UA might, separately, have limits on how long of a custom property they can support,
or how large of an identifier they can support.
This section calls out this attack specifically
because of its long history,
and the fact that it can be done without any of the pieces
<em>seeming</em> to be too large on first inspection.



<!--
Expand Down Expand Up @@ -706,5 +751,9 @@ Privacy and Security Considerations {#priv-sec}
===============================================

This specification defines a purely author-level mechanism for passing styling information around within a page they control.
As such, there are no new privacy considerations.

As such, there are no new privacy or security considerations.
[[#long-variables]] calls out a long-standing Denial-of-Service attack
that can be mounted against "macro-expansion"-like mechanisms,
such as the ''var()'' function,
and mandates a defense against that attack.

0 comments on commit 5e36a2e

Please sign in to comment.