-
Notifications
You must be signed in to change notification settings - Fork 509
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
3rd party CSS, Font, XHR, IMG and JS reveals your browsing site by request header 'Origin' attribute #509
Comments
This comment has been minimized.
This comment has been minimized.
that's because the number of sites that use someone else's CSS is slim to none (except for google fonts and as you already noticed in most or all cases those don't leak origin). So in that sense origin doesn't leak anything that the CDN doesn't already know anyway, namely that a certain CSS belongs to a certain site. But regardless of that I personally only allow 1st party css by default anyway.
github uses
👍 |
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
Sadly far from what I see. Maybe you see it that way as you block most 3rd party's. For someone who does not, the reality is different.
As we see, its not in the real world. Even github is using Origin in a websocket requests. |
but it's not really someone else's CSS, is it? It may be hosted on some CDN but it's only used by that site, no? I mean who would use someone else's CSS for his/her own site? that's just silly. The 3rd party changes something and all of a sudden your page looks different? really? |
CMS Templates are shared by many different sites. |
I guess that's possible but arent' templates usually installed into the CMS and then hosted and served by the domain using the CMS? btw according to https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes even |
Wordpress Themes are used by many, as Joomla, Blogger, even Jekyll on GH Pages. |
This comment has been minimized.
This comment has been minimized.
We need additional rule for CORS... see #506 (comment) if (detail.type === 'font' || detail.type === 'script' || detail.type === 'stylesheet') {
for (let a in val) {
if (val[a].name.toLowerCase() === 'access-control-allow-origin') { return; }
}
val.push({'name': 'Access-Control-Allow-Origin', 'value': detail.originUrl.split('/', 3).join('/')});
} What we do here is to check if CORS is set, in that case we do not alter anything. We might get some better performance with regex for the line (@claustromaniac help 😄) val.push({'name': 'Access-Control-Allow-Origin', 'value': detail.originUrl.split('/', 3).join('/')}); Test page (note the icons with or without this additional rule): OT: @earthlng... for better performance add Still in ToDo: XHR, WebSocket, IMG. Cheers |
It seems the pattern is too simple for a regex to give a significant performance benefit here, at least on my end (YMMV). You can test here if you want: Another alternative (didn't test this one): val.push({'name': 'Access-Control-Allow-Origin', 'value': (new URL(detail.originUrl)).origin});
val.push({'name': 'Access-Control-Allow-Origin', 'value': detail.originUrl}); EDIT: NVM, it's not. I just tested it. |
If performance is not a concern, not breaking out of the loop is safer because servers can include multiple The same goes for In the case of the |
BTW, you shold probably check that the value of the ACAO header is not "null" if found, just in case. It is a bad practice but some servers do that, and Firefox will not fetch the resource in that scenario. Another tip: you can use a for...of loop since Like this: if (detail.type == 'font' || detail.type == 'script' || detail.type == 'stylesheet') {
for (const a of val) {
if (a.name.toLowerCase() == 'access-control-allow-origin') {
if (a.value == "null") {a.value = detail.originUrl.split('/', 3).join('/');}
return;
}
}
val.push({'name': 'Access-Control-Allow-Origin', 'value': detail.originUrl.split('/', 3).join('/')});
} |
^^ @claustromaniac thank you for the upper tip and rework (and help overall). 👍 From what I see now, we have a working solution for Fonts, CSSs and JSs.., see updated first post. OT:
I am aware of that, but didn't found a single case now browsing around, but of course it doesn't mean its not there somewhere or will be in the future. The same goes for using I am using fiddler where I am tagging all For now, there are XHRs and WebSockets left to investigate and, oh man, the XHRs are really bad, broadcastings Origins all around the globe. EDIT: I have reedited this whole post. |
Yeah, that's a good way to put it. 😆 Reading through https://w3c.github.io/webappsec-cors-for-developers/ more carefully, I think it is worth noting that these rules can involve some serious risks. Summarizing, we are trading off security for privacy. If I understand correctly, this is how CORS works, in a nutshell: spoiler
Typical situation:
What happens when we use these rules:
The problem is that, in practice, we are giving up the same-origin policy for this, which is risky. Here is why: spoiler
Alternatively, this could be solved by a simple dedicated extension. Said extension would have to check whether the Cookie header is present in the request headers, and only remove the Origin header if it is not. Then, if it did remove the Origin header, it would have to check the response headers for that specific request and add/modify the ACAO header so it says Anyway, I think people should be warned of this. There is a good reason for these headers to exist, and that reason is not something that many would easily give up (such as performance). |
Even with whitelisting CORS as in #509 (comment) ? |
We are trading off security for privacy by whitelisting CORS. BTW what that rule does is not really whitelisting, it's more like enforcing CORS 😛. I'm sorry to say I don't think I can explain it any better than I already did. The same-origin policy and CORS are messy concepts that take a while to comprehend. I don't fully comprehend them myself, TBH. |
Its prematurely to say, but IMHO, what we are doing here should be safe for Fonts and CSSs. |
Maybe drop |
Yes, probably. Besides, if I understand correctly, there are various ways to mitigate the bad side effects of that rule. I believe that even without taking any special precautions the risk is likely low, but I thought it was worth pointing it out anyway. |
IMHO no. All it can do bad, is to lead to unforeseen breakages, but I haven't found any till now. |
Breaking same-origin policy isn't matter of breakage but security #509 (comment) and using separate browser isn't a fix. |
@claustromaniac
Its wrong, it should be: The response rule actually doesn't know the site A. @Maryse47 Using a separate browser for banking/paying was never meant as a fix, but as a best practice. |
It does. If you want to confirm, you can use a rule like this in HE: if (detail.type == 'font' || detail.type == 'script' || detail.type == 'stylesheet') {
console.log(
`-----------------------------------
Resource at
${detail.url}
has this originUrl:
${detail.originUrl}`);
} Save it as a rule to modify response headers and check the browser console (with CTRL+SHIFT+J) while you browse.
My bad. I should've made that part clearer. My example implied that site B was the banking site. In that example, site A would be a random malicious site, and a resource from site A would request your private data to your banking site (site B). So, it wouldn't be your bank making requests to a third party, it would be another site making requests to your bank (your bank would be the third party). I should probably edit that comment, just in case. Even then, it is pretty hard to explain... for me, at least. EDIT: OK, I edited that part of the comment. I hope it is easier to understand now. |
Now that I think about it, some sites may also rely on the same-origin policy for practical reasons, not just for security. Since web developers wouldn't expect common users to tamper with headers, in some scenarios it could be reasonable for them to attempt to make several requests for different resources and let the same-origin policy filter out the unnecesary ones, instead of doing that filtering by other means. This is just theoretical, though. |
Thx @claustromaniac ... I will get back to the drawing board as soon I have time. |
From what I have browsed and monitored in the last days, the First post updated. |
Note to myself: Libraries at Also, @earthlng mentioned possible abusements over There are abusements over referers, but this is covered by ghacks-user.js out-of-the-box. I am currently logging possible discrepancies over console with if (detail.type === 'font' || detail.type === 'stylesheet' || detail.type === 'image') { return; }
for (const header of val) {
if (header.name.toLowerCase() === 'origin') {
var headerOrigin = header.value;
break;
}
}
if (headerOrigin === 'undefined') { return; }
// testing if different domain and filtering out same domain
if (!(detail.url.split('/', 3)[2].endsWith(headerOrigin.split('//')[1].replace('www.','')))) {
console.log(`ORIGIN_ALERT: ${detail.type}
S: ${detail.originUrl}
D: ${detail.url}
O: ${headerOrigin}`
);
} Log output:
There will be also false positives in the output (but it can be identified as such by naked eye). EDIT: Added |
The cache must be cleared, otherwise it would not show. You are fantastic. |
Is it possible to whitelist per destination? I have tried several video sources, like: youtube, twitch, twitter, imdb... with an exception where I haven't tried FB.
I am just thinking out loud... but in that case you would avoid requests (issues) to add additional parameters or the |
^^ To simplify the upper shitload, could you just add a whitelist for XHR destination to Cheers |
It is not currently possible to whitelist individual resources, but I considered the idea last week. I kinda wanted to avoid implementing that, but I think that will be the best way to go about this, because it will require almost no maintenance in the long term. It is also more flexible and everything. I think I'll use a syntax like the one you proposed. Something like I'll try to do it in the next few days. With that the extension will be feature-complete at last 😅 Then I'll have to write the documentation and all that, which is the boring part. |
This comment has been minimized.
This comment has been minimized.
ˇˇ Don't worry, nothing to understand... I must have been eaten something "strong" that day, since you have already implemented that. I will update that post and remove the confusing and embarrassment part. |
@claustromaniac Its working perfect. Thank you. Cheers OT: |
OK... a small bug there is. Now add Cheers |
I meant to do a release today; it's been over two weeks already. I only have to do some final retouches and finish the documentation. |
I have tried now with a clean profile with only this extension and can reproduce every time. |
I misread this part:
That is not how overrides work. Overrides rely on the document URL (the URL in your URL bar). To accomplish what you tried to do I would have to implement a sort of blacklist (similar to the exclusions that I released yesterday, but for blacklisting). |
Oh... I see. |
The problem is I don't see any efficient way to do that, because I'd have to parse headers in all requests to achieve that... I'd have to rewrite the whole |
I mean, I can do it, but I will be throwing out all the efficience-driven logic. Right now it's using fail-fast patterns to save CPU cycles, but I'll have to rewrite all that... hm... or maybe I can use an alternative callback for when there are items in the blacklist, and the extension will only be inefficient then, but that's like doubling the lines of code in It would take some time. I think I'd prefer to do the EDIT: NVM, I think I overestimated the problem. I think I know what I'll do. |
Thank you @crssi for your early work to block this tracking method and for helping @claustromaniac as s/he developed POOP. I finally replaced CorsE and your Header Editor rule with POOP ver. 1.1.0. @claustromaniac, your knowledge and generosity impress me. Thank you for creating and offering this extension. It should be adopted by everyone, right alongside their favorite adblockers. |
Thank you, but the heavy lifting was done by the @claustromaniac. |
@Woofy-Wolf, glad to help! |
We have found Jesus. It disguises as @claustromaniac . |
Is he Portuguese?! |
I want to leave it open, because I think we should do something more about it (learn more about it myself, maybe add it to the wiki, etc ) - open issues are my personal todo checklist - just like we still have the EvilCorp AMP issue open |
I have created an experimental extension aiming to provide complete user control over CORS, including plugging this Origin header leak. Might anyone be interested? Feedbacks needed. Thank you |
Thanks @tartpvule ... I'll keep out of this conversation (as I have up til now) as I'm not up to date or even qualified about all of this. I'm not sure where @claustromaniac - he's been missing for about 3 or 4 weeks - maybe he went on holiday or got locked in the neighbor's garage or something. Cats are pretty amazing creatures, so I expect he'll show up soon 🐈 |
I keyed into the bold request of the first item wrongly selecting the first request option 'cancel'. It was entertaining having no functional web. Oops. |
Very nice, @tartpvule. Not user-friendly, if you ask me, but your extension certainly seems to give more control (which was the main goal, I guess). When I can, I think I will update the documentation of my POOP extension (thinking back on it... man, what an honest name!) and link to yours while I'm still not actively maintaining it. I should have done that long ago, actually, but I've been kind of DEAD for a while. Now... which of my several dozen notifications should I pick next?... |
if you want to do anything with this: e.g add it to the wiki, then reopen or just tell me |
Most 3rd party CSS, Font and JS reveals you browsing site by request header
Origin
attribute.I know that a lot of you block fonts by default and JS sometimes or most the times, but most of you do not block CSS.
So it might be of your interest to remove
Origin
attribute from request header for CSS and Font.JS (and XHRs too) can be covered by good uBO blocklists.
You can use Header Editor web extension to remove those.
Rule type: Modify the request header
Match type: All
Execute type: Custom function
Code:
We need an additional rule to work in pair with upper script:
Rule type: Modify the response header
Match type: All
Execute type: Custom function
Code:
What I don't know is, how much this action could add to unique fingerprint in a real world.
From logging traffic in a week of browsing, I could not find single case whereOrigin
attribute would be used in XHR requests to the addresses of the different owner as the browsing site is.This issue is a follow up of #506
The text was updated successfully, but these errors were encountered: