Looks like he edited it to remove now but parent comment was basically saying he's been telling customers to avoid shared hosting by using shared hosting in the form of Heroku, etc instead.
I've never seen a userdir URL being used with anything but raw static HTML with no or little JS. Generally the type of people who use these hosts don't use cookies or local storage at all. They just want to post a few web pages, photos, or documents. Can someone find an example?
Most userdir hosting allows you to run CGI, PHP and whatever other scripting supported by Apache. Stuff that required a persistent connection to the server (I.e. WSGI) usually isn't supported... almost every cPanel host out there is set up in this manner... Unfortunately the path part of a URL is not used for same origin, so the security issue being floated is real for myhost.com/~someuser.
The only place I've seen these used are universities (eg each professor gets a webspace) and other small companies and organizations. I think it's relatively safe to assume Alice isn't going to attack Bob—if she did want to, she has better ways to do so.
Now, if someone knows of a host selling ~username spaces to members of the public, that's a different story.
In most of the places where you get the ~username sites the users themselves have non-root UNIX accounts and they can't really install things on their own. (Well they can install it in their own home folder but that's it; won't affect other people.) Even the web server is centrally managed and the user only provides static HTML.
Except what the article is about; because all sites are on the same domain and origin all sites security affects all other sites security. A page on one site has the right to manipulate all pages on another site.
> Even the web server is centrally managed and the user only provides static HTML
In other news php has suddenly ceased to exist and javascript is no longer a thing. Sorry, handwaving the problem away does not work.
When I see ~username I know I'm about to load a page with some cream tiled background. These days every user just gets their own subdomain like username.usersites.com
I've only ever seen userdir URLs hosting static content - ideally, static HTML with lesson plans or a resume or something. Why would anyone host a web application on a userdir? This seems like a complete non-issue.
Also - why would a blog be threatened by XSS? A blog is a collection of static HTML files and I assume the creator would be using a composer or just a text editor + browser to add and edit pages. Why would anyone log into a blog? Nowadays anything like a comment section is generally handled by iframes to some other service (like Disqus) anyway.
> Also - why would a blog be threatened by XSS? A blog is a collection of static HTML files and I assume the creator would be using a composer or just a text editor + browser to add and edit pages. Why would anyone log into a blog?
Perhaps you've never heard of WordPress [0], the 17-year-old blogging software used by ~60 million web sites as of 2012 [1] and that is, today, "the platform of choice for over 35% of all sites across the web" [2]?
I have experience using Wordpress; in sixth grade I tried out the Wordpress editor and felt writing HTML was easier. I admit it's popular with less-savvy users and with companies with money to burn, but it seems unprofessional to use Wordpress for anything you can write by hand. I don't think anyone would be using blogging software if they didn't have their own domain.
This is a non-problem. There is no real threat model. It's like how you can cast to my TV if you're in my house. Sure, anyone could attack the party by posting porn on the TV but that's really not going to happen because I'm not going to invite you and put you in the wifi if you're the kind of person who does that.
Technically speaking, there could be a security vulnerability on a dynamic site that is being hosted with mod_userdir, even though the owner of it is "trusted". With that model, if the security vulnerability is exploited by a third party to attack a different mod_userdir user, then it's not really about who you trust to invite, since the entire Internet is technically invited.
Exactly correct. Even in the early 90s best practice was to house your user webspaces at users.isp.net/~user. Even now the most exciting thing you could do with this is use JavaScript to submit a contact form from another users webspace.
This is like complaining that Geocities users shared a security domain. Surprise, there was nothing of value hosted there to start with.
Also, example.com/~username style URLs usually are 1990s-style static web sites where the only Javascript is something like a marquee. They are not the kinds of sites which have extensive Javascript or a web forum people can sign in to; at most a site like that would have a guestbook.
Are you kidding? It's a standard feature of Apache, used by universities all over the place. Many shared hosting providers offered the feature for customers that weren't ready to update their DNS to the new host, until quite recently.
People do turn malicious. One of the biggest sources of attacks in computer security is current and former users.
After all, if we didn't need to care about user level security, why don't we let everyone be root? Surely we only created accounts for people we can trust, right?
I'm not saying that your point isn't valid that the exposure here isn't very small. I'm just saying that your logic isn't really very sound.
It would have been much easier to say that if weaponised, an XSS vulnerability can access resources across the entire domain as if they were the victim, and should effectively be considered an account hijack of any exploited victims.
It really has nothing to do with homepaths, or even user-supplied data whatsoever.
Here's a threat model. My university used to give students /~s123456 folders. On the same domain as the main student platform, and as the main university site. I'm not sure if they still do this but it was less than 3 years ago. Considering the age of the infrastructure, there's even a good chance that session cookies were not marked HttpOnly. Even if they weren't, I can put a login form on my page, and even if the user doesn't get tricked into using it through phishing, if their browser autocompletes it I now have their username and password.
Now yes, our uni probably shouldn't be giving out userdirs to all students, much like wifi, you should only let in the people you trust. But that's exactly the point of the article.
You'd think this was just an archaic relic but Bambora payment processing (which hasn't updated their site since uppercase HTML tags and framesets were a thing) has a userdir feature that lets their customers upload static file to their "secure webspace" which is hosted on the same domain for all customers.
> All userdir URLs on one server run on the same host and thus are in the same origin. It has XSS by design.
The ship has now sailed, but I still think it's worth pointing out that it is Javascript's security model that is broken by design, that XSS vulnerabilities are the result, and the same origin policy is an incomplete workaround as illustrated by the article. This becomes clear when you consider that userdir URLs pre-date Javascript.
The public suffix list is yet another incomplete workaround for the security flaw in the same origin policy (that "same origin" isn't a concept that can be clearly defined).
The modern web stack is a security house of cards, as demonstrated.
Honestly I can't think of a much better system that can support a billion websites. What would you change/overhaul about the current system if you could ignore compatibility?
I still think it's a miracle that the browser was the solution to the client-server problem x-windows was trying to solve all along.
X was the solution to the problem MIT had, and as such, the problem X was trying to solve. It worked very, very well for what it was trying to solve.
How we ended up with billions of people able to interact with an app that we can all build at home seems insane...
Java. Java did this. On billions of devices! Everywhere from your smart card to the mainframe. Before Java, Dis! Before Dis, Forth! Good luck running a web browser plus your application on a smart card, or even (decently) on an underpowered netbook.
Good luck running a web browser plus your application on a smart card, or even (decently) on an underpowered netbook.
Sufficiently young people probably suspect these were called netbooks as some joke. They run Emacs just fine and without constantly swapping, but a web browser?
They’re fine little web browsers if you manage to enable web browser acceleration for the integrated intel video card.
If not, they can’t even run JavaScript ads, because apparently ads like to refresh the screen with a static image at 60fps. Software rasterizers can’t keep up with that (even on 32 core, >200W TDP xeons, from what I’ve seen...)
The web really sucks at everything other than network effects.
Being complete garbage didn’t stop JavaScript either :/
At least JS had the excuse of being designed and implemented by a single developer in three weeks. X Windows was part of Project Athena, a $50 million project from MIT, DEC, and IBM with a five-year schedule.
X worked great for what it was aiming to do. It's not even bad for really remote applications. It works really well, just don't use a dozen layers of poorly-designed abstraction. Write something with xcb or xlib, and you'll get instantaneous response from the other side of the planet.
Here's a nice little article from 1989 telling just how great it was for the time:
Eh, that’s a nice fluff piece but doesn’t match my understanding or experiences working with X. Once X had more widespread adoption in the 1990s you started to see a lot more hate.
The layers of abstraction are there because X is such a godawful piece of shit. Sure, your application will be fast if you only use XCB or Xlib (and XCB is just a modern replacement for Xlib, made because of how deeply flawed Xlib is, and it can’t even fully replace Xlib). But few people are willing to put in the blood, sweat, and code to write something that is pure X.
So if X worked great for what it was aiming to do, it was aiming to do the wrong thing.
X was hated when it got widespread adoption because people began using it for things it wasn't intended for. X was aiming to do the right thing.
Sure, if you're using it to connect to a box in Canada over a satellite connection in Johannesburg during 1995 with countless abstractions, you're going to have a horrible time. Use the right tool for the job.
X-Windows IS a dozen layers of poorly-designed abstraction, itself. To the core. Most of which nobody even uses any more. But is still required to be there. And yes, it is extremely bad for remote applications.
>XTool was very small and fast compared to the X sample server because I wrote the server from scratch. I think that I'm the only person to write an X server outside of the X Consortium. One of the things that I learned by doing it was that the X Consortium folks were wrong when they said that the documentation was the standard, not the sample server. There were significant differences between the two.
>The only really worthwhile thing about X was the distributed extension registration mechanism. All of the input, graphics and other crap should be moved to extension #1. That way, it won't be mandatory in conforming implementations once that stuff was obsolete. As you probably know, that's where we are today; nobody uses that stuff but it's like the corner of an Intel chip that implements the original instruction set. As an aside, I upset many when working on OpenDoc for Apple and saying the same thing there.
>The atom/property mechanism allows clients to allocate memory in the server that can never be freed. Some way to free memory needs to be added.
>The bit encodings should be part of a separate language binding, not part of the functional description.
>Had he done some real design work and looked at what others were doing he might have realized that at its core, X was a distributed database system in which operations on some of the databases have visual side-effects. I forget the exact number, but X includes around 20 different databases: atoms, properties, contexts, selections, keymaps, etc. each with their own set of API calls. As a result, the X API is wide and shallow like the Mac, and full of interesting race conditions to boot. The whole thing could have been done with less than a dozen API calls.
I like it better than VNC or RDP, especially on a fast network.
Those others I think get it wrong with their "whole desktop" sharing. The experience of having X clients streamed as they are launched and the local WM gets to manage decorations - I like that model a lot more, for say the scenario where I ssh into a machine and launch a GUI program.
RDP is much faster than X. It had the benefit of being designed later I guess.
VNC usually feels laggier than X to me somehow. As if there is a cursor sync issue.
If you honestly can’t think of one, that only demonstrates your lack of imagination.
I, for one, would imagine something based on a DNS TXT records that either directly contain or point to a URL describing some kind of security domain policy: whether and which subdomains and subdirectories should be considered separate, isolated security domains, with pattern matching, of course. Or maybe put it under /.well-known/ instead of DNS. At the very least, this would solve the unregistration problem of PSL (i.e. when an entry becomes stale, you will not immediately know it, and old versions of your product will still treat it as present).
It's a reasonable hack though. Where else do you put "how to interact with this domain" data, you can't serve that data (eg via http) because clients need to already know how to interact with that domain before they interact with that domain?
Firstly, I'd fix the damn spelling of the referer header instead of everybody putting up with it for close to 30 years.
I don't think it's that JavaScript and HTML are a bad choice, but there are some things that would have made life a lot easier if they were strongly enforced sooner, including secure cookies by default, SameSite=lax, removal of referer header and CSP - doing them sooner would have stopped bad developer practices while also removing a fair chunk of application security complexities, but at least we're moving towards a better world regarding those now.
I don't know if it'd be technically possible to implement, but additional characters to mark unsafe strings would have a huge impact on webapp security. Reflection of untrusted data at the moment generally relies on one of: HTML encoding, URL encoding or JavaScript escaping and escaping a safe way is highly context-dependent (I've seen an unescaped "\n" cause injection within JavaScript contexts). A way of effectively storing the level of trust a chunk of data has across multiple transports when marking untrusted data including within HTML/JS, SQL statements and interpreted languages like BASH or PHP - this would eliminate a bunch of vulnerabilities and would probably have mitigated a bunch of notable historic vulnerabilities and/or hacks.
> HTML encoding, URL encoding or JavaScript escaping and escaping a safe way is highly context-dependent (I've seen an unescaped "\n" cause injection within JavaScript contexts)
I have had a hard time convincing co-workers that if you have php generating sql generating (! yes!) html generating javascript, you need to escape the string for javascript since it's embedded in javascript. Then you need the string escaped for html since it's embedded in html. Then you need the string escaped for sql since it's embedded in sql. Only then can you chuck it into the middle of the string. It is better to not do such craziness; but once you've decided to do such craziness, you must do it properly. The similarities between js and mysql escaping are irrelevant; it must be escaped properly each time it is embedded in another language.
What a supremely stupid suggestion. It solves basically none of the problems escape characters do.
How would it allow you to write a regex that matches a dot? Or text in an XML element that includes an ampersand?
Even for quotes contained in string literals it's a shitty solution because string literals are part of programming languages and having to count characters every time you change a String literal is just about the last thing you want in your language (and it would be horrible to read as well).
Commenter above, correct me if I’m misinterpreting, but — I imagine they meant for when programs talk to other programs. Regexes and string literals are written by humans; it would be easy for the compiler/program to calculate the length for you.
The general solution is parametric construction. When we're building SQL queries, regular expression matchers, HTML files, etc., we're actually attempting to build a richer data structure but representing it as a flat string. Instead of concatenating strings, we can turn our original string into one where some leaf nodes are placeholders for future literal entities, which can be substituted for their actual values without fear of potential metacharacters that could be misinterpreted.
While the solution may be fairly clear, not everyone provides easy interfaces for parametric construction--regular expression engines being the one where the lack is the most distressing for me (although this is less because I need to substitute in user-generated strings and more because I want to combine smaller regexes into larger ones to make the regex easier to follow).
>How would it allow you to write a regex that matches a dot?
You could write
1:.
>Or text in an XML element that includes an ampersand?
The point is to not use XML, because it has escape characters. You could replace it with ASN.1 BER
>Even for quotes contained in string literals it's a shitty solution because string literals are part of programming languages and having to count characters every time you change a String literal is just about the last thing you want in your language (and it would be horrible to read as well).
Irrespective of who's right or wrong it's pretty unnecessary to call each other names just because you don't agree, particularly when the question is theoretical and has almost no real world impact.
I’m curious what you mean by this — why does coding for length prevent streaming? The receiving end can certainly treat the text as a stream still. Do you mean that the sender cannot “stream” if they are generating the contents on the fly? That seems trivial to solve - just break it up into chunks, assuming a little bit of buffering is OK.
The better solution is allow control over what the terminating characters are. Rust raw strings allow N ‘#’ characters around them, like r”x”, r#”x”, r#####”x with “quotes””#####. So no escapes are ever needed, just increase the number of hashes to outstrip the maximum consecutive hashes appearing in the string after a quote character.
“ The misspelling of referrer originated in the original proposal by computer scientist Phillip Hallam-Baker to incorporate the field into the HTTP specification.[4] The misspelling was set in stone by the time of its incorporation into the Request for Comments standards document RFC 1945; document co-author Roy Fielding has remarked that neither "referrer" nor the misspelling "referer" were recognized by the standard Unix spell checker of the period.[5] "Referer" has since become a widely used spelling in the industry when discussing HTTP referrers; usage of the misspelling is not universal, though, as the correct spelling "referrer" is used in some web specifications such as the Document Object Model.”
I have to disagree that the misspelling "referer" has "become a widely used spelling" even with the qualification "in the industry when discussing the HTTP referrers", a qualification too specific to be useful, in my opinion. In my experience getting the spelling wrong leads to much frustration and annoyance to this day.
Make applications into a single file that can pull aditional xml and json data, images and video by appending the session key. If the application desires to do something other than display the data the user must give permission. No more checking if the json has a key but map it to a dom element and make that [and all its parents] unreadable.
(Keep all the legacy crap for when this is not enough)
> What would you change/overhaul about the current system if you could ignore compatibility?
Say, you have some endpoints which can do a public key crypto signature verification. Part of the cookie data is such an endpoint URL. If a script loaded into a page wants to read a cookie, the endpoint defined by the cookie checks the signature of the script and the browser accordingly allows or not access to the cookie. As you'd sign the scripts during deployment, the private key is not even on the public servers.
For performance reasons probably wouldn't send the entire script just a hash of it so it's like GET https://example.com/check?hash=1234567890&signature=abcdef and there's a simple 200 or 403 response. You could make the API such that you can bundle multiple hashes and signatures together so the entire overhead over the network is a single request for every endpoint. If you want to be fancy, you can have a response body for the 403 response which tells the browser something like "this hash is of an outdated version, plz ignore cache and load a new one".
Secrets stored in cookies really shouldn't be accessible, the Set-Cookie HttpOnly flag should stop all JS access to a cookie. The HttpOnly flag still submits a cookie when you do an ajax GET/POST, but you cannot access the cookie via document.cookie or similar.
There's also external resource integrity checks which prevent modification of third party resources without breaking the local site. jQuery CDN code snippets do this by default: https://code.jquery.com/ .
You can't trust one script to access a cookie without trusting all scripts to access the same cookie though - while I can see some merit to the idea when it comes to hiding secrets from XSS/untrusted code, I'd say that in most (99.9%) situations effort would be better spent actually implementing CSP and good data sanitation rather than caring about implementing JavaScript level trust models.
For the same-origin problem, the web server could return an Origin header which defines the origin. So the server on example.org could serve https://example.org/~username for anything in that account. The defined origin would have to be under the scheme, domain, and port served by the server, of course.
I think their point was that the concept could be expanded as per their suggestion, as a simple way to fix the security issues.
Having the server send a 'this is my site base' header would be helpful even without having path support. At the moment, browsers need to magically know about all multi-level domains, like example.co.uk, so that they don't lump together all *.co.uk domains as the same site.
If website is non-trivial, i. e. user have to login to it, I would encrypt all urls with client-specific key. So that it is non-sharable and unforgable
Unless I'm missing something, it seems that this would eliminate most of the issues raised in the article by using a separate subdomain for each user/site.
Using lighttpd, you can do this with this very simple configuration [0]:
You can specify Path attribute for cookie and it will only be sent to URls with this prefix. I'm not completely sure, but I think that it should solve those security flaws.
If you own example.com and want to have cookies accessible in the root (e.g. example.com/login.html) then you can't prevent example.com/users/~evildoer from accessing them.
Don't we have equivalent problems with evildoer.example.com trying to get and set example.com cookies? Hence why Google and Github and other major sites use separate domain for user hosted content vs first party content.
It would not. It would stop the cookie from being sent to things outside of the path specified, but the Same Origin Policy is about, among other things, gaining read-access to the responses of fetch/XMLHttpRequest/AJAX requests.
If there is a cookie set for the path '/secret' and I can host content at '/attacker', then some of my JavaScript under /attacker could do a fetch request to /secret/something. This fetch request would carry the cookie for /secret, and the response would be readable by my JavaScript (due to Same Origin Policy). I could read the response, extract sensitive content, or even extract CSRF tokens to allow me to do state-changing CSRF-protected things under /secret
I tested with SameSite being Lax and Strict. Neither block the attack in Chrome. My reading of the SameSite spec indicates that it doesn't take cookie path into account.
> The public suffix list is yet another incomplete workaround for the security flaw in the same origin policy (that "same origin" isn't a concept that can be clearly defined).
Origins are very clearly and rigorously defined[0].
It's just that people have a tendency to group multiple applications/users on the same origin. Now, would it be nice to optionally allow servers to be more restrictive? Sure. There are a few privacy implications there, but I could easily see someone making a case for that. I think I'd possibly support an HTML directive that allowed you to have a stricter same-origin policy (ie, restrict to current URL, or restrict to parent path).
At the same time, setting up subdomains that point to static directories is really stinking easy. And I am skeptical that any web host that refuses to use subdomains is going to care enough about security to opt-in to an even more aggressive scheme. A website that is hosting 3rd-party sites via userdirs is a website that will ignore or circumvent any security model you propose.
> The public suffix list is yet another incomplete workaround for the security flaw in the same origin policy
No, the opposite. The public suffix list is a workaround for the flawed security model of cookies. In your focus on Javascript, you are missing the much bigger problem. See below:
> there is however still a caveat with this: Unfortunately the same origin policy does not apply to all web technologies and particularly it does not apply to Cookies.
The same-origin policy is (overall) fine, the problem is that the old web security model didn't have it. So we are trying to retroactively build a modern security model based on strict, on-by-default isolation on top of a flawed security model that assumed every single domain would be owned by a single entity. Cookie "contexts" are a lot broader than modern definitions of "origins". They can be inherited from parent domains, they can be trivially shared across domains without user consent. And they also aren't by-default isolated across userdirs.
This has all turned out to be, broadly, a bad idea. While I don't think the same-origin policy is perfect, it's pretty obviously better than what we were using before. This is why you're seeing movement from the Chrome team to turn on SameSite isolation by default for cookies. Because we look back at the original web security model and realize that opt-in SameSite and randomized form-submit tokens for security were always a mistake.
All of this is dancing around that you mention that userdir URLs pre-date Javascript. To be clear, userdir URLs were inherently insecure from the moment they were conceived. You should not have been hosting websites this way, even before Javascript existed.
To the extent that people got away with this kind of thing before Javascript, it was only because userdir websites were so ridiculously limited that they often didn't have any serverside capabilities to respond to form submissions, or to run any kind of logic at all. To the extent that people weren't widely phished on userdir-hosted sites by fake forms with hidden fields that sent logic to parent origins or to other sites they were already logged into, it's only because the web was so young and so tiny that we were able to get away with bad security -- the same way that in a rural area I can get away with leaving my garage unlocked.
I'm not exactly happy with every decision modern browsers are making about the direction of web security, but I would challenge anyone to look at the history of CSRF mitigations and then say that the same-origin policy is not a universally better security model for Javascript to adopt.
I think you’re ignoring the fact that the browser security model is based on a flawed definition of an origin that prohibits something that has very little reason not to work. Userdir sites weren’t/aren’t limited at all. If you dropped a php file into your directory it would run.
domain.suffix/full/path should have been the definition of an origin because people were literally using it as such. The default config of the most popular web server at the time was doing it. People hosted entirely different sites in subdirectories because it was really easy to just create a directory. TV ads directed people to www.blahblah/sitename.
The real definition of origins is clever since the path before the domain defines an origin path and everything after is owned by that origin. Neat and tidy for sure but broke userspace so to speak.
But that's never how userspace was ever designed to work during the web's history. Hosting sites this way, especially commercial ones, was always insecure because of the way cookies were designed from day one.
Same-site policies broke userspace in the same sense that Wayland is breaking X11 userspace by making it so applications can't just send keypresses to each other. Userspace was already broken, it was an insecure mess -- it's just that we recognize it now. If you were running a userdir site that supported PHP, you probably should not have been doing that.
I'm glad nothing got hacked for the people doing it, but I used to leave my bike unchained at the library growing up, and it didn't get stolen either -- didn't make it secure. I believe you that there was a time when companies advertised on TV using userdirs, because I know there was a time when Facebook only used SSL for its login screen and when Twitter forced users to enable SSM account recovery. Companies do insecure crap sometimes :)
If you don't care about same-site security, then nothing's broken -- the vulnerabilities you're exposed to now in a post-Javascript world for userdir sites are the same ones you were exposed to back then. It's just users today are more likely to actively exploit them.
I'm in no way saying that it wasn't a broken insecure mess and needed fixing -- just that the fix that actually happened broke some already established ways of organizing websites. Any website that relied on that doing naughty things with cookies that crossed logical boundaries they weren't supposed to -- sure -- makes total sense to break them. But having one site at mysite.com/a and another at mysite.com/b is a perfectly valid use cause and ought to have had a path to being secure instead of being fundamentally insecure which is what we have now.
Like doesn't it seem a little silly that you can't make a.mysite.com and mysite.com/a behave the same way?
The current system is mostly consistent with the way that SSL UX works, it's consistent with the way modern browsers display URLs. From an engineering perspective it's silly, but we're also thinking about ways to easily get across to users 'who owns the thing you're looking at'. It's also nice to have a rigid boundary somewhere, because it allows us to turn on isolation by default; the same-origin policy isn't something programmers have to remember to opt into. So there's UX questions like, "by default should cookies only resolve to a single URL, and programmers have to whitelist subpaths? Would any of the web operators doing this today care enough to actually implement an optional security feature?"
All that being said, I'm broadly sympathetic to an argument that same-origin policies didn't go far enough. I think you can make a very reasonable argument that origins are pretty arbitrary, and that the problems I list above are solvable, and that regardless of the original design we should adapt to what users want to do. That's a fine position to take.
I'm not sympathetic to the top-level argument I was originally responding to; that Javascript has fundamentally made things worse, or that the same-origin policy is a house of cards waiting to collapse, or that that browser policies like same-origin and SameSite aren't basic security improvements over what the web used to be before JS. The truth is, while imperfect, web browser security is still (broadly) very good. I question if there is any user-accessible native platform that comes even close to the web in having decent process/network/data isolation. There is no house of cards collapsing, in reality most native platforms like phones are largely playing catch-up to implement the same sandboxing features that the web has had for nearly a decade.
I get that's not the argument you're making, you're looking at this through the lens of, "should this be supported?". And again, that's reasonable. I do want to re-emphasize though; if you still want to host using userdirs, no browser capabilities have been removed, and nothing is any more insecure than it used to be. You're using the word 'broke', I'm not sure I get what you mean by that. There was an insecure thing people were doing, and they can still do it today with the same consequences. Nothing has fundamentally changed.
> by default should cookies only resolve to a single URL, and programmers have to whitelist subpaths?
That sounds sensible! I always wondered why the origin and cookie scope isn’t limited to the full URL of the resource that set it and only explicitly extendable by something like <link rel=“same-origin”...>
Basically make every URL it’s own security and permissions sandbox but allow the programmer some latitude to extend it (and probably the administrator of parent directories/domains some capability to restrict how far up/across the tree a URL can reach, with the default perhaps being to allow only within same domain and path.)
noticing a lot of comments about how this is a “javascript” problem. i just want to clarify whether or not people are asserting this is a _language design_ issue, or an implementation of the runtime specifically within the context of web browsers and web servers?
IMO, yes and no. The language design isn’t to blame. The libraries and runtime that are colloquially known as JS are. It’s hard to separate the two in discussion so the term js is a bit overloaded.
No, it has very little if anything to do with Javascript. My charitable reading is that people are using JS as a colloquial term to refer to the Web as a platform in general.
To the extent that it's a browser problem at all, it's a problem with how browsers as a platform handle HTTP requests and site-isolation, which is a security system that predates Javascript.
Thanks for pointing this out because I was just going to say the same thing. It’s most definitely not a Javascript problem, as Javascript is just a language, and nothing about the language design is inherently insecure. The problems are with the implementation of the browsers’ security mechanisms, some of which are indeed controlled via JS.
The issue is an injection attack. The ability to insert either unsanitised HTML data or data reflected inside the context of a JavaScript code block which results in JavaScript execution (by <script> tags, being able to specify data in DOM element events such as onClick or onError, or being able to specify code in onClick/onError events). I don't consider this a flaw in JavaScript itself, rather how JavaScript is harnessed from HTML.
Once JavaScript execution is obtained* it's possible to inject a JavaScript keylogger and/or rewrite the DOM to request authentication details from the victim (resulting in credential compromise). Alternatively, it's possible use AJAX to perform GET/POST requests to the same domain, routed through the victims browser which includes all cookies etc - effectively this is a time-boxed account compromise (CSRF controls do not apply when requests are executed from the local domain).
It's also possible to coerce a browser into triggering the exploit in a hidden iframe on a completely different page (eg you browse to evil.com, there's a hidden iframe which exploits an XSS vulnerability on facebook.com, compromising your facebook account if your currently logged into facebook on the exploited browser). I'm pretty sure samesite=strict only fix this if the XSS vector on facebook.com requires the user to be authenticated prior to exploitation, similarly, samesite=lax will not prevent attacks which require authenticated POST primitives.
*I'm a pentester, so that's sometimes my job, I don't break laws.
> The modern web stack is a security house of cards, as demonstrated.
Perhaps, but I feel like major recent changes are fixing most of these vulnerabilities:
1. Content Security Policy locks down most of the vulnerabilities that result from something on a page being able to contact something from a different origin. Of course, it's not set by default and these days requires a lot of trial and error to figure out the "right" way to set it, but it solves a lot of issues.
2. On the cookie front, the recent changes to the default SameSite behavior also pretty much end CSRF bugs.
Would you provide links elaborating your both points? I haven't kept myself up to date with the web's security and I'm curious how those two problems were solved.
1. Like you already hinted at, it is really difficult to get right, and I hardly experience any larger website (with multiple teams working on it) that implement it effectively. So while it's great in theory, I'm not sure if it's accessible enough (and therefore effective enough) for most of the world.
2. I'm assuming you're talking about Chrome's SameSite value; it's worth to note that this has been rolled back a short while ago because of compatibility issues in larger government organizations having to be accessible especially now with COVID-19. More info here: https://9to5google.com/2020/04/03/chrome-rolls-back-cookie/
1. It's not really hard to get right, it just takes a lot of trial and error. I.e. you essentially start with the default-src as 'self', and then create exceptions to other resources as you need them. You use the report-uri/report-to endpoints to get reports if either (a) you've neglected to open up a resource you need, or (b) you DO have a vulnerability that someone is trying to take advantage of. While this may sound like a bit of a pain, e.g. if you have multiple teams working on a website that all need to access their set of 3rd party endpoints, this pain is required for good security: it forces you to be explicit about the 3rd party endpoints you allow, instead of the browser just allowing any endpoint for things like script tags, imgs, etc. which is the default now.
2. Note what Chrome is rolling back is the SameSite default change. SameSite has existed for quite some time now, in all browsers, it's just that the default is currently 'None' in Chrome but is changing to 'Lax'. So you can still take advantage of this now, it's just Chrome is delaying changing the default so that it doesn't break sites who aren't prepared for the default change.
So my point is the tools currently available really tighten up the sandbox guarantees of the browser, and make it no more difficult than necessary to build a secure site.
HTML is based on XML and even if you remove JavaScript, you could still create XML tags and attributes that lead to malicious behaviour and information leaks.
Want to guess which vulnerability jumped from not being in the OWASP top 10 to being in the 4th place? XML External Entities (XXE).
HTML is based on SGML. XML is a subset of SGML. XHTML is HTML converted to valid XML. IANAE, but I suspect most problems originate with SGML, which was designed for flexibility and extensibility rather than security. That’s compounded by the sprawling complexities of both HTML and XML that easily masks weaknesses and holes and makes implementation very hard to verify. Road to Hell, etc.
Ridiculous. The solution isn't to call public_html bad. The solution is to encourage people who are going to run things like webmail and other sites with Javascript like that to use a specific virtualhost for webmail.
Would be nice if we included a path in the spec for single origin. It's almost as if the spec was designed to kill off public_html style share hosting... either that or talk the control panel software people into using subdomains instead of paths for userdirs.
Sure, if you're running entirely separate systems behind each username.
But in that case this has been true since XHR first came into existence 15-20 years ago: https://en.wikipedia.org/wiki/XMLHttpRequest (sub)domains are a fundamental requirement for web security, they essentially always have been.
Today we have affordable wildcard CA-signed SSL certificates (thanks Let's Encrypt!) so there's no excuse for not following https://username.host/ structures.
User-specific subdomains have their own set of problems too. This is why, for example, GitHub Pages switched their hosting from username.github.com to username.github.io - even with HTTPSOnly cookies, you can still set cookies for other subdomains.
I would argue that the root issue you're describing which leads to XSS on the same host is allowing un-sanitized input leading to code injection.
It is entirely possible to design your own application which uses unique userdirs without using any of Apache's built in functionality that are completely immune to XSS because it is not possible for any of the users to place malicious scripts on the server.
Likewise it is also entirely possible to build a web app that doesn't use userdirs at all in any form for anything and still be vulnerable to XSS because of underlying input sanitization or code injection problems.
So whatever you're going to do, just do your homework and do it well.
What? No. mod_userdir is not dangerous. The resulting URLs are not dangerous.
Having multiple unrelated unvetted outside users with the ability to make your server serve arbitrary JavaScript is dangerous. The route you take to get there is kind of beside the point.
If anything, mod_userdir is helpful in that it's obvious when content is under the control of a different user. Perhaps browsers should treat x.com/~x/ as a different server from x.com/~y/ for XSS purposes.
This is not a problem of userdir but of Javascript. Userdir is older, then JS arrived and introduced many kinds of vulnerabilities, then some of these have been addressed, with mixed results. With userdir you're perfectly fine if you don't use JS.
136 comments
[ 2.2 ms ] story [ 173 ms ] threadIt was vulnerable to the attacks described here. Thankfully no-one on that domain ever exploited it in that way.
Now, if someone knows of a host selling ~username spaces to members of the public, that's a different story.
Except what the article is about; because all sites are on the same domain and origin all sites security affects all other sites security. A page on one site has the right to manipulate all pages on another site.
> Even the web server is centrally managed and the user only provides static HTML
In other news php has suddenly ceased to exist and javascript is no longer a thing. Sorry, handwaving the problem away does not work.
Also - why would a blog be threatened by XSS? A blog is a collection of static HTML files and I assume the creator would be using a composer or just a text editor + browser to add and edit pages. Why would anyone log into a blog? Nowadays anything like a comment section is generally handled by iframes to some other service (like Disqus) anyway.
Perhaps you've never heard of WordPress [0], the 17-year-old blogging software used by ~60 million web sites as of 2012 [1] and that is, today, "the platform of choice for over 35% of all sites across the web" [2]?
---
[0]: https://wordpress.org
[1]: https://web.archive.org/web/20160129215921/http://www.forbes...
[2]: https://wordpress.org/about/
This is like complaining that Geocities users shared a security domain. Surprise, there was nothing of value hosted there to start with.
Edit: The "true" marquee was running in the now defunced status bar (window.status) via JS.
After all, if we didn't need to care about user level security, why don't we let everyone be root? Surely we only created accounts for people we can trust, right?
I'm not saying that your point isn't valid that the exposure here isn't very small. I'm just saying that your logic isn't really very sound.
It really has nothing to do with homepaths, or even user-supplied data whatsoever.
Now yes, our uni probably shouldn't be giving out userdirs to all students, much like wifi, you should only let in the people you trust. But that's exactly the point of the article.
The ship has now sailed, but I still think it's worth pointing out that it is Javascript's security model that is broken by design, that XSS vulnerabilities are the result, and the same origin policy is an incomplete workaround as illustrated by the article. This becomes clear when you consider that userdir URLs pre-date Javascript.
The public suffix list is yet another incomplete workaround for the security flaw in the same origin policy (that "same origin" isn't a concept that can be clearly defined).
The modern web stack is a security house of cards, as demonstrated.
How we ended up with billions of people able to interact with an app that we can all build at home seems insane...
X was the solution to the problem MIT had, and as such, the problem X was trying to solve. It worked very, very well for what it was trying to solve.
How we ended up with billions of people able to interact with an app that we can all build at home seems insane...
Java. Java did this. On billions of devices! Everywhere from your smart card to the mainframe. Before Java, Dis! Before Dis, Forth! Good luck running a web browser plus your application on a smart card, or even (decently) on an underpowered netbook.
Sufficiently young people probably suspect these were called netbooks as some joke. They run Emacs just fine and without constantly swapping, but a web browser?
If not, they can’t even run JavaScript ads, because apparently ads like to refresh the screen with a static image at 60fps. Software rasterizers can’t keep up with that (even on 32 core, >200W TDP xeons, from what I’ve seen...)
The web really sucks at everything other than network effects.
Hardware acceleration makes things slower, not faster.
> Software rasterizers can’t keep up with that (even on 32 core, >200W TDP xeons, from what I’ve seen...)
You're nuts. Software rasterizers keep up with DOS games just fine, even on an old 386.
It's the fact that they're trying to use Javascript and other garbage-collected or object-oriented languages to code these rasterizers.
At least JS had the excuse of being designed and implemented by a single developer in three weeks. X Windows was part of Project Athena, a $50 million project from MIT, DEC, and IBM with a five-year schedule.
Here's a nice little article from 1989 telling just how great it was for the time:
https://simson.net/clips/1989/1989.TechRev.Athena.pdf
The layers of abstraction are there because X is such a godawful piece of shit. Sure, your application will be fast if you only use XCB or Xlib (and XCB is just a modern replacement for Xlib, made because of how deeply flawed Xlib is, and it can’t even fully replace Xlib). But few people are willing to put in the blood, sweat, and code to write something that is pure X.
So if X worked great for what it was aiming to do, it was aiming to do the wrong thing.
Sure, if you're using it to connect to a box in Canada over a satellite connection in Johannesburg during 1995 with countless abstractions, you're going to have a horrible time. Use the right tool for the job.
The X-Windows Disaster
https://medium.com/@donhopkins/the-x-windows-disaster-128d39...
>X: The First Fully Modular Software Disaster
https://news.ycombinator.com/item?id=17056516
John Steinhart wrote XTool, a nice snappy reimplementation of X11 on top of SunView! ;)
https://web.archive.org/web/20171008204348/https://minnie.tu...
X and NeWS History
https://news.ycombinator.com/item?id=15325226
Jon Steinhart wrote:
>XTool was very small and fast compared to the X sample server because I wrote the server from scratch. I think that I'm the only person to write an X server outside of the X Consortium. One of the things that I learned by doing it was that the X Consortium folks were wrong when they said that the documentation was the standard, not the sample server. There were significant differences between the two.
>The only really worthwhile thing about X was the distributed extension registration mechanism. All of the input, graphics and other crap should be moved to extension #1. That way, it won't be mandatory in conforming implementations once that stuff was obsolete. As you probably know, that's where we are today; nobody uses that stuff but it's like the corner of an Intel chip that implements the original instruction set. As an aside, I upset many when working on OpenDoc for Apple and saying the same thing there.
>The atom/property mechanism allows clients to allocate memory in the server that can never be freed. Some way to free memory needs to be added.
>The bit encodings should be part of a separate language binding, not part of the functional description.
>Had he done some real design work and looked at what others were doing he might have realized that at its core, X was a distributed database system in which operations on some of the databases have visual side-effects. I forget the exact number, but X includes around 20 different databases: atoms, properties, contexts, selections, keymaps, etc. each with their own set of API calls. As a result, the X API is wide and shallow like the Mac, and full of interesting race conditions to boot. The whole thing could have been done with less than a dozen API calls.
Recommendation: People who like saying "X-Windows" also enjoy saying "Project Anathema".
Those others I think get it wrong with their "whole desktop" sharing. The experience of having X clients streamed as they are launched and the local WM gets to manage decorations - I like that model a lot more, for say the scenario where I ssh into a machine and launch a GUI program.
RDP is much faster than X. It had the benefit of being designed later I guess.
VNC usually feels laggier than X to me somehow. As if there is a cursor sync issue.
These are just my observations as a user.
I, for one, would imagine something based on a DNS TXT records that either directly contain or point to a URL describing some kind of security domain policy: whether and which subdomains and subdirectories should be considered separate, isolated security domains, with pattern matching, of course. Or maybe put it under /.well-known/ instead of DNS. At the very least, this would solve the unregistration problem of PSL (i.e. when an entry becomes stale, you will not immediately know it, and old versions of your product will still treat it as present).
How would you do it?
I don't think it's that JavaScript and HTML are a bad choice, but there are some things that would have made life a lot easier if they were strongly enforced sooner, including secure cookies by default, SameSite=lax, removal of referer header and CSP - doing them sooner would have stopped bad developer practices while also removing a fair chunk of application security complexities, but at least we're moving towards a better world regarding those now.
I don't know if it'd be technically possible to implement, but additional characters to mark unsafe strings would have a huge impact on webapp security. Reflection of untrusted data at the moment generally relies on one of: HTML encoding, URL encoding or JavaScript escaping and escaping a safe way is highly context-dependent (I've seen an unescaped "\n" cause injection within JavaScript contexts). A way of effectively storing the level of trust a chunk of data has across multiple transports when marking untrusted data including within HTML/JS, SQL statements and interpreted languages like BASH or PHP - this would eliminate a bunch of vulnerabilities and would probably have mitigated a bunch of notable historic vulnerabilities and/or hacks.
I have had a hard time convincing co-workers that if you have php generating sql generating (! yes!) html generating javascript, you need to escape the string for javascript since it's embedded in javascript. Then you need the string escaped for html since it's embedded in html. Then you need the string escaped for sql since it's embedded in sql. Only then can you chuck it into the middle of the string. It is better to not do such craziness; but once you've decided to do such craziness, you must do it properly. The similarities between js and mysql escaping are irrelevant; it must be escaped properly each time it is embedded in another language.
The formats could be so simple: first the length of the data, then raw data of that length
How would it allow you to write a regex that matches a dot? Or text in an XML element that includes an ampersand?
Even for quotes contained in string literals it's a shitty solution because string literals are part of programming languages and having to count characters every time you change a String literal is just about the last thing you want in your language (and it would be horrible to read as well).
While the solution may be fairly clear, not everyone provides easy interfaces for parametric construction--regular expression engines being the one where the lack is the most distressing for me (although this is less because I need to substitute in user-generated strings and more because I want to combine smaller regexes into larger ones to make the regex easier to follow).
You could write
>Or text in an XML element that includes an ampersand?The point is to not use XML, because it has escape characters. You could replace it with ASN.1 BER
>Even for quotes contained in string literals it's a shitty solution because string literals are part of programming languages and having to count characters every time you change a String literal is just about the last thing you want in your language (and it would be horrible to read as well).
The IDE could update the length automatically
“ The misspelling of referrer originated in the original proposal by computer scientist Phillip Hallam-Baker to incorporate the field into the HTTP specification.[4] The misspelling was set in stone by the time of its incorporation into the Request for Comments standards document RFC 1945; document co-author Roy Fielding has remarked that neither "referrer" nor the misspelling "referer" were recognized by the standard Unix spell checker of the period.[5] "Referer" has since become a widely used spelling in the industry when discussing HTTP referrers; usage of the misspelling is not universal, though, as the correct spelling "referrer" is used in some web specifications such as the Document Object Model.”
(Keep all the legacy crap for when this is not enough)
Say, you have some endpoints which can do a public key crypto signature verification. Part of the cookie data is such an endpoint URL. If a script loaded into a page wants to read a cookie, the endpoint defined by the cookie checks the signature of the script and the browser accordingly allows or not access to the cookie. As you'd sign the scripts during deployment, the private key is not even on the public servers.
For performance reasons probably wouldn't send the entire script just a hash of it so it's like GET https://example.com/check?hash=1234567890&signature=abcdef and there's a simple 200 or 403 response. You could make the API such that you can bundle multiple hashes and signatures together so the entire overhead over the network is a single request for every endpoint. If you want to be fancy, you can have a response body for the 403 response which tells the browser something like "this hash is of an outdated version, plz ignore cache and load a new one".
There's also external resource integrity checks which prevent modification of third party resources without breaking the local site. jQuery CDN code snippets do this by default: https://code.jquery.com/ .
You can't trust one script to access a cookie without trusting all scripts to access the same cookie though - while I can see some merit to the idea when it comes to hiding secrets from XSS/untrusted code, I'd say that in most (99.9%) situations effort would be better spent actually implementing CSP and good data sanitation rather than caring about implementing JavaScript level trust models.
https://tools.ietf.org/html/rfc6454#section-7
Having the server send a 'this is my site base' header would be helpful even without having path support. At the moment, browsers need to magically know about all multi-level domains, like example.co.uk, so that they don't lump together all *.co.uk domains as the same site.
Unless I'm missing something, it seems that this would eliminate most of the issues raised in the article by using a separate subdomain for each user/site.
Using lighttpd, you can do this with this very simple configuration [0]:
Add a "wildcard" record for "*.users.example.org" pointing to the proper host to your DNS zone and you're all set.---
[0]: https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_Mod...
Cookies are a terrible security model in general.
If there is a cookie set for the path '/secret' and I can host content at '/attacker', then some of my JavaScript under /attacker could do a fetch request to /secret/something. This fetch request would carry the cookie for /secret, and the response would be readable by my JavaScript (due to Same Origin Policy). I could read the response, extract sensitive content, or even extract CSRF tokens to allow me to do state-changing CSRF-protected things under /secret
Origins are very clearly and rigorously defined[0].
It's just that people have a tendency to group multiple applications/users on the same origin. Now, would it be nice to optionally allow servers to be more restrictive? Sure. There are a few privacy implications there, but I could easily see someone making a case for that. I think I'd possibly support an HTML directive that allowed you to have a stricter same-origin policy (ie, restrict to current URL, or restrict to parent path).
At the same time, setting up subdomains that point to static directories is really stinking easy. And I am skeptical that any web host that refuses to use subdomains is going to care enough about security to opt-in to an even more aggressive scheme. A website that is hosting 3rd-party sites via userdirs is a website that will ignore or circumvent any security model you propose.
> The public suffix list is yet another incomplete workaround for the security flaw in the same origin policy
No, the opposite. The public suffix list is a workaround for the flawed security model of cookies. In your focus on Javascript, you are missing the much bigger problem. See below:
> there is however still a caveat with this: Unfortunately the same origin policy does not apply to all web technologies and particularly it does not apply to Cookies.
The same-origin policy is (overall) fine, the problem is that the old web security model didn't have it. So we are trying to retroactively build a modern security model based on strict, on-by-default isolation on top of a flawed security model that assumed every single domain would be owned by a single entity. Cookie "contexts" are a lot broader than modern definitions of "origins". They can be inherited from parent domains, they can be trivially shared across domains without user consent. And they also aren't by-default isolated across userdirs.
This has all turned out to be, broadly, a bad idea. While I don't think the same-origin policy is perfect, it's pretty obviously better than what we were using before. This is why you're seeing movement from the Chrome team to turn on SameSite isolation by default for cookies. Because we look back at the original web security model and realize that opt-in SameSite and randomized form-submit tokens for security were always a mistake.
All of this is dancing around that you mention that userdir URLs pre-date Javascript. To be clear, userdir URLs were inherently insecure from the moment they were conceived. You should not have been hosting websites this way, even before Javascript existed.
To the extent that people got away with this kind of thing before Javascript, it was only because userdir websites were so ridiculously limited that they often didn't have any serverside capabilities to respond to form submissions, or to run any kind of logic at all. To the extent that people weren't widely phished on userdir-hosted sites by fake forms with hidden fields that sent logic to parent origins or to other sites they were already logged into, it's only because the web was so young and so tiny that we were able to get away with bad security -- the same way that in a rural area I can get away with leaving my garage unlocked.
I'm not exactly happy with every decision modern browsers are making about the direction of web security, but I would challenge anyone to look at the history of CSRF mitigations and then say that the same-origin policy is not a universally better security model for Javascript to adopt.
[0]: https://developer.mozilla.org/en-US/docs/Web/Security/Same-o...
domain.suffix/full/path should have been the definition of an origin because people were literally using it as such. The default config of the most popular web server at the time was doing it. People hosted entirely different sites in subdirectories because it was really easy to just create a directory. TV ads directed people to www.blahblah/sitename.
The real definition of origins is clever since the path before the domain defines an origin path and everything after is owned by that origin. Neat and tidy for sure but broke userspace so to speak.
But that's never how userspace was ever designed to work during the web's history. Hosting sites this way, especially commercial ones, was always insecure because of the way cookies were designed from day one.
Same-site policies broke userspace in the same sense that Wayland is breaking X11 userspace by making it so applications can't just send keypresses to each other. Userspace was already broken, it was an insecure mess -- it's just that we recognize it now. If you were running a userdir site that supported PHP, you probably should not have been doing that.
I'm glad nothing got hacked for the people doing it, but I used to leave my bike unchained at the library growing up, and it didn't get stolen either -- didn't make it secure. I believe you that there was a time when companies advertised on TV using userdirs, because I know there was a time when Facebook only used SSL for its login screen and when Twitter forced users to enable SSM account recovery. Companies do insecure crap sometimes :)
If you don't care about same-site security, then nothing's broken -- the vulnerabilities you're exposed to now in a post-Javascript world for userdir sites are the same ones you were exposed to back then. It's just users today are more likely to actively exploit them.
Like doesn't it seem a little silly that you can't make a.mysite.com and mysite.com/a behave the same way?
The current system is mostly consistent with the way that SSL UX works, it's consistent with the way modern browsers display URLs. From an engineering perspective it's silly, but we're also thinking about ways to easily get across to users 'who owns the thing you're looking at'. It's also nice to have a rigid boundary somewhere, because it allows us to turn on isolation by default; the same-origin policy isn't something programmers have to remember to opt into. So there's UX questions like, "by default should cookies only resolve to a single URL, and programmers have to whitelist subpaths? Would any of the web operators doing this today care enough to actually implement an optional security feature?"
All that being said, I'm broadly sympathetic to an argument that same-origin policies didn't go far enough. I think you can make a very reasonable argument that origins are pretty arbitrary, and that the problems I list above are solvable, and that regardless of the original design we should adapt to what users want to do. That's a fine position to take.
I'm not sympathetic to the top-level argument I was originally responding to; that Javascript has fundamentally made things worse, or that the same-origin policy is a house of cards waiting to collapse, or that that browser policies like same-origin and SameSite aren't basic security improvements over what the web used to be before JS. The truth is, while imperfect, web browser security is still (broadly) very good. I question if there is any user-accessible native platform that comes even close to the web in having decent process/network/data isolation. There is no house of cards collapsing, in reality most native platforms like phones are largely playing catch-up to implement the same sandboxing features that the web has had for nearly a decade.
I get that's not the argument you're making, you're looking at this through the lens of, "should this be supported?". And again, that's reasonable. I do want to re-emphasize though; if you still want to host using userdirs, no browser capabilities have been removed, and nothing is any more insecure than it used to be. You're using the word 'broke', I'm not sure I get what you mean by that. There was an insecure thing people were doing, and they can still do it today with the same consequences. Nothing has fundamentally changed.
That sounds sensible! I always wondered why the origin and cookie scope isn’t limited to the full URL of the resource that set it and only explicitly extendable by something like <link rel=“same-origin”...>
Basically make every URL it’s own security and permissions sandbox but allow the programmer some latitude to extend it (and probably the administrator of parent directories/domains some capability to restrict how far up/across the tree a URL can reach, with the default perhaps being to allow only within same domain and path.)
is this a js problem?
To the extent that it's a browser problem at all, it's a problem with how browsers as a platform handle HTTP requests and site-isolation, which is a security system that predates Javascript.
Once JavaScript execution is obtained* it's possible to inject a JavaScript keylogger and/or rewrite the DOM to request authentication details from the victim (resulting in credential compromise). Alternatively, it's possible use AJAX to perform GET/POST requests to the same domain, routed through the victims browser which includes all cookies etc - effectively this is a time-boxed account compromise (CSRF controls do not apply when requests are executed from the local domain).
It's also possible to coerce a browser into triggering the exploit in a hidden iframe on a completely different page (eg you browse to evil.com, there's a hidden iframe which exploits an XSS vulnerability on facebook.com, compromising your facebook account if your currently logged into facebook on the exploited browser). I'm pretty sure samesite=strict only fix this if the XSS vector on facebook.com requires the user to be authenticated prior to exploitation, similarly, samesite=lax will not prevent attacks which require authenticated POST primitives.
*I'm a pentester, so that's sometimes my job, I don't break laws.
Perhaps, but I feel like major recent changes are fixing most of these vulnerabilities:
1. Content Security Policy locks down most of the vulnerabilities that result from something on a page being able to contact something from a different origin. Of course, it's not set by default and these days requires a lot of trial and error to figure out the "right" way to set it, but it solves a lot of issues.
2. On the cookie front, the recent changes to the default SameSite behavior also pretty much end CSRF bugs.
2. I'm assuming you're talking about Chrome's SameSite value; it's worth to note that this has been rolled back a short while ago because of compatibility issues in larger government organizations having to be accessible especially now with COVID-19. More info here: https://9to5google.com/2020/04/03/chrome-rolls-back-cookie/
2. Note what Chrome is rolling back is the SameSite default change. SameSite has existed for quite some time now, in all browsers, it's just that the default is currently 'None' in Chrome but is changing to 'Lax'. So you can still take advantage of this now, it's just Chrome is delaying changing the default so that it doesn't break sites who aren't prepared for the default change.
So my point is the tools currently available really tighten up the sandbox guarantees of the browser, and make it no more difficult than necessary to build a secure site.
HTML is based on XML and even if you remove JavaScript, you could still create XML tags and attributes that lead to malicious behaviour and information leaks.
Want to guess which vulnerability jumped from not being in the OWASP top 10 to being in the 4th place? XML External Entities (XXE).
But in that case this has been true since XHR first came into existence 15-20 years ago: https://en.wikipedia.org/wiki/XMLHttpRequest (sub)domains are a fundamental requirement for web security, they essentially always have been.
https://github.blog/2013-04-05-new-github-pages-domain-githu... and https://github.blog/2013-04-09-yummy-cookies-across-domains/ are relevant
It specifically mentions that and even names github.io as an example.
It is entirely possible to design your own application which uses unique userdirs without using any of Apache's built in functionality that are completely immune to XSS because it is not possible for any of the users to place malicious scripts on the server.
Likewise it is also entirely possible to build a web app that doesn't use userdirs at all in any form for anything and still be vulnerable to XSS because of underlying input sanitization or code injection problems.
So whatever you're going to do, just do your homework and do it well.
Having multiple unrelated unvetted outside users with the ability to make your server serve arbitrary JavaScript is dangerous. The route you take to get there is kind of beside the point.
If anything, mod_userdir is helpful in that it's obvious when content is under the control of a different user. Perhaps browsers should treat x.com/~x/ as a different server from x.com/~y/ for XSS purposes.