Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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?


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.


Escape characters are one of the most stupid things in the computing world.

The formats could be so simple: first the length of the data, then raw data of that length


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.


But then we would never be able to treat text as a stream. All of your one pass algorithms would become two pass.


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.


[flagged]


>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).

The IDE could update the length automatically


> You could write 1:.

So separate wildcards and literals, each prepended by length? That would be far, far less readable than using escape sequences.

> The point is to not use XML, because it has escape characters. You could replace it with ASN.1 BER

Fair enough, but most people would consider that a solution worse than the problem.

> The IDE could update the length automatically

Making you completely dependent on an IDE to support whatever format you're editing, including nesting. You can't even read your code now without an IDE. Making up some kind of DSL on the fly? Start counting string lengths again.

Sorry, but no. Escape sequences are bad, this would so much worse.


>So separate wildcards and literals, each prepended by length? That would be far, far less readable than using escape sequences.

Wildcards do not need a prefix, when they always are a single character.

Here is a ordinary regex for a path:

    C:\\foo\\bar\\.*\.txt
And here the regex in C:

    "C:\\\\foo\\\\bar\\\\.*\\.txt"

But with lengths in a hypothetical syntax:

    11:C:\foo\bar\.*4:.txt


    22:11:C:\foo\bar\.*4:.txt
That is quite readable

> You can't even read your code now without an IDE. Making up some kind of DSL on the fly? Start counting string lengths again.

I like binary formats. The lengths are easy to see in a hex editor. 16 bytes in each line or something

You always depend on an IDE to decode the file. You could not read an UTF-8 file, if it would not decode the UTF-8 characters and show individual bytes. Or read ASCII if it were showing individual bits.


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.


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).


Which would, again, only help with delimiters, but not with other characters that have special meaning but also need to be used literally.


From https://en.wikipedia.org/wiki/HTTP_referer

“ 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.


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.


This is not true; a URL with anything past the port is not a valid "origin"

https://tools.ietf.org/html/rfc6454#section-7


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.


Yes, this was my meaning - apologies if i wasn't clear.


This is brilliant and simple and backwards-compatible. Well done. If I knew anything about the standards process I would write an RFC for it today.


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.

How we ended up with billions of people able to interact with an app that we can all build at home seems insane...


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.


> They’re fine little web browsers if you manage to enable web browser acceleration for the integrated intel video card.

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.


If X-windows wasn't complete garbage at actually providing remote applications then it may have had a chance.


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:

https://simson.net/clips/1989/1989.TechRev.Athena.pdf


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.

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.


Thank you for saying "X-Windows". ;)

Recommendation: People who like saying "X-Windows" also enjoy saying "Project Anathema".


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.

These are just my observations as a user.


It's been said that NeWS could have been the web.


Pretty much all modern web servers support per-user virtual hosts using wildcards that allow for URLs like http://username.users.example.org/ (instead of http://users.example.org/~username/ when using mod_userdir).

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]:

  $HTTP["host"] =~ "users\.example\.org" {
      evhost.path-pattern = "/home/%4/public_html/" 
  }
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...


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


Isnt that contrary to the point of urls?


> 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.


Yes, the server signing its scripts would do it, provided the server doesn't blindly sign attacker-submitted code. Some servers might...


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)


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).


Using DNS TXT to solve a XSS issue? That's clearly another card added to the house.


IMO, using DNS for anything other than hostname lookups is a complete hack. I'm looking at you, SPF.


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?

How would you do it?


Transport encryption with PKI.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: