Custom Properties as State
css-tricks.com
css-tricks.com
> What happens when you combine the fact that part after the : for CSS Custom Properties doesn’t need to be valid CSS with window.getComputedStyle()? You get a way of passing data – including Arrays, Objects, and even JSON – from CSS to JavaScript.
The first article proposes the possibility of sending updated variables via a CDN, and the linked one shows a CSS variable being parsed as JSON and then executed by the Javascript engine.
There's probably some fun and high jinks to be had there…
[1] https://www.bram.us/2020/03/30/pass-data-from-css-to-javascr...
I haven't tried this, but this should have the same effect:
.sneaky-class:before {
content: '{"tracking_code": "abc"}';
display: none;
}
const trackingPayload = JSON.parse(
window.getComputedStyle(
document.querySelector(".sneaky-class"),
":before")
.getPropertyValue("content")
);The only issue I can think of is mixing code/data with styling information. Otherwise there is no "issue" per se.
> What does this circumvent that cannot be done with pure JS?
Nothing, it is just JS after all, and the idea that you can store data in other things than JS variables is not new (jQuery days we stored data in various attributes in the DOM to keep track of state). You could also store the same data in <title/> tag and get the same results. Not sure what the use case is, except it's a fun little hack.
Maybe this will spawn some new JS framework, nothing would surprise me anymore.
Except for enjoying a web without styles, there is no reason to disable CSS (together with disabling JS). You're not gonna prevent any more JS fudgery by having JS and CSS disabled compared to just JS disabled.
Since you understand how a browser works much better than I do, tell me, can I disable XHR while still running JS?
From the article:
> CSS as an API?
> This makes me think that a CDN-hosted CSS file like this could have other useful stuff, like today’s date for usage in pseudo content, or other special time-sensitive stuff. Maybe the phase of the moon? Sports scores?! Soup of the day?!
> It’s almost like a data API that is tremendously easy to use.
Nope, I can't see any problem with JS being able to receive data from an external API, but then I have a lack of understanding of how JS and CSS work in the browser.
The reason why this css thing is not a major problem is that the js could retrieve this data just as easily using one of the other methods I listed. JS retrieving data from an external API is generally not a problem unless its used for tracking purposes or as part of an cross site scripting attack.
At worst, this gives online tracking companies yet another tool in their toolbox. I am sure the boffins down at ublock are already working on detecting and mitigating this behaviour.
I can’t really see it being used for cross site attacks unless some whackadoodle site decided to try and send secreted authenticated data via CSS payloads.
uMatrix can do it, I'm sure there are others
> fetch
fetch is a Javascript API and covered by uMatrix's XHR setting[1].
> web rct
That can be disabled[2] and is also covered by uMatrix's XHR setting.
> iframes
Can be blocked in several ways, including the aformentioned uMatrix.
> At worst, this gives online tracking companies yet another tool in their toolbox
At worst CSS in the browser has had a CVE[3] and OWASP has some attacks[4] that seem old, but you know which of these have been fixed by all the browser vendors you use, right? Perhaps you've read this paper[5] on scriptless attacks and you know that all of these have been mitigated?
> The surprising result is that an attacker can also abuse Cascading Style Sheets (CSS) in combination with other Web techniques like plain HTML, inactive SVG images or font files. Through several case studies, we introduce the so called scriptless attacks and demonstrate that an adversary might not need to execute code to preserve his ability to extract sensitive information from well protected websites. More precisely, we show that an attacker can use seemingly benign features to build side channel attacks that measure and exfiltrate almost arbitrary data displayed on a given website.
Even better, you have the faith that there will never be a repeat of these kind of things and that no attackers will bother to go down this route in future. What part does faith have when deciding upon the risks of running things downloaded from untrusted sources?
Still, the anti-tracking is good enough reason for me.
> I am sure the boffins down at ublock are already working on detecting and mitigating this behaviour.
Let's hope so.
[1] https://github.com/gorhill/uMatrix/wiki/The-popup-panel#the-...
[2] https://www.ivacy.com/internet-privacy/disable-webrtc-leak/
[3] https://cve.circl.lu/cve/CVE-2011-0132
[4] https://owasp.org/www-community/xss-filter-evasion-cheatshee...
[5] https://www.nds.ruhr-uni-bochum.de/media/emma/veroeffentlich...
Sure, but it's not easy. You'd have to run content-scripts from some browser extension that polyfills the APIs you want to get rid of. But disabling XHR/fetch/others won't stop your browser from being able to make requests. CSS can make requests (like when you provide custom font paths, or images), HTML can also make requests (<img> and <iframe> elements comes to mind). Without those, we don't have a web anymore, we have a document storage without links to other resources.
CSS cannot be used as an external API as much as HTML cannot be used as an API. The trick the author is talking about under "CSS as an API" assumes that JS is activated, otherwise you can't really do anything dynamic with the data. And if you're not doing something dynamic (like you wanna display some text in :content under a :before element), you can just set it in the HTML response instead of in the CSS response.
I'm not saying that disabling JS by default is bad (I do so myself, enabling it only for trusted sites). I'm just pointing out that disabling CSS is not gonna give you any additional benefits. As long as you're in the browser, a HTML page can make requests for you, even if you have CSS disabled.
I have XHR disabled by default and can enable it with 2 clicks.
> But disabling XHR/fetch/others won't stop your browser from being able to make requests.
> CSS can make requests
Hence it being disabled.
> HTML can also make requests (<img> and <iframe> elements comes to mind).
Which is why I have those disabled by default too.
> CSS cannot be used as an external API as much as HTML cannot be used as an API
But it can be used as an API and because there are people out there, like yourself, who downplay this ability, there are those who will leave it running…
> assumes that JS is activated, otherwise you can't really do anything dynamic with the data
…and hence, may have disabled the usual routes that you listed - XHR, images, frames etc - and leave JS on for some other reason while believing they've mitigated a number of major threats.
It's hard to produce perfect security or anti-tracking behaviour, very hard, but that doesn't mean we should ignore CSS.
I also can't make Lynx and Wget into a more graphical form with just a couple of clicks, and there are other reasons reasons to disable CSS[1][2] but each to their own.
[1] https://medium.com/javascript-in-plain-english/tracking-with...
[2] https://www.templarbit.com/blog/2018/03/20/tracking-users-wi...
classic cross domain ad tracking trick. BUT seems like chrome is trying to limit by keying caches to the domain. BUT BUT maybe not in cross domain web workers?
IDK though might be some interesting ideas. *edit maybe just cname cloak like are doing to get around itp
poc: https://github.com/dillondoyle/css_cache https://dillondoyle.github.io/css_cache/index.html
- basic js generates a css file with a random uuid and an example just my name. puts into a css var as a JSON object
- sets long term cache headers AND a matching etag (same as uuid)
- etag is a classic tracking trick but this is really cool it makes it accessible as state in JS client side
- index.html prints/logs the css var- if css file is cached the uuid you see is static. no cookies needed
- i was also going to add just an array of recent request domains, last and first session. would help test the chrome cache keying. could even put a jwt in there
it's just a cool hack I never thought of. it's really cool how one thing can trigger an 'omg that's so obvious' brain fart.
Like even before CSS vars you could have done this just set really specific css width 12.999933/122.3333 or something then measure the div you set or maybe simpler just a random "'uuid_"+the_uuid_var+"'" classname add to body and then read if it exists with js. But I never thought of it until I saw this article!!! Same with just generating a JS file with static var which I've played with but never deployed. though I might guess a css file is cached longer? idk i don't have proof of that just a guess could be wrong
could maybe extend this to get around chrome cache keying with cname cloaking *edit actually maybe more likely that doesn't make sense idk i'd have to think about it
or just reading their docs last night about their new policy (only a couple months old) it looks like webworkers aren't enforced yet and you can explicitly control & cache a file with JS in a webworker
In fairness the author talks about using them very dynamically (rip cache), which is a bit different, but still its just an extension of the basic idea of setting a variable.
So, the more things you can move over into CSS, the more things exist in this beautiful pure context that's highly debuggable thanks to modern browser tooling (and that's not even getting into the performance advantages vs doing things in JS).
Put simply: it's really exciting every time CSS gets a new "real programming language" feature, even if these things are basic and familiar in other programming contexts. In this case we're not really getting a "new" feature, but people are used to thinking of CSS variables as like, a theming mechanism. I for one had never thought to use them as an API data format. The author is probing the boundaries of what's possible to do with them, and that's exciting and interesting.
As an aside: there's also a huge community that loves to just push and abuse HTML/CSS as far as they can for the sport of it. CSS-Tricks and its sibling-site CodePen are at the center of that community. To people like that, the idea of an API endpoint that uses a stylesheet to relay raw data for arbitrary usage is pretty cool.
And by "state" I mean it in its proper sense: something where CSS itself can mutate its own state. The OP calls CSS custom properties "state", but they're really just "constants" in the context of CSS itself (they can only be mutated by JS).
For example see the css implementation of celluar autonoma http://eli.fox-epste.in/rule110/
You're right that HTML (technically, the DOM) has a little bit of intrinsic state, despite our mental model of it being static. However that state is constrained to user interaction and is always very localized, so it avoids most of the maintainability problems that we think of as coming from having mutable state
You'd have a separate theme.css that defined the new variables. Because of CSS variables you can keep the main style.css and all the markup the same.