It's as I feared: What was previously a nearly-compatible-with-HTTP, dead-simple protocol, looks to have become confusingly, unnecessarily complex. Like XMPP.
It will catch on because it's all we've got, but we're going to shove yet another mediocre protocol onto the stack of protocols servers need to speak in addition to HTTP.
The people working on this have spent time understanding the problem domain better than I have. But I really hope they've thought this protocol through. Because we'll be stuck with it for a long time.
A lot of bad protocols exist because people didn't think it through enough and a lot of bad protocols exist because people thought it through too much.
The security protocol does seem a little strange: putting numbers into the fields interspersed with random characters and spaces, taking the numbers and dividing them by the number of space characters, and using 2 fields to make harder. There's a lot of dancing here to ensure that the protocol is implemented correctly.
The IETF is an open forum where anyone can participate. If you want your voice heard, join the mailing list and make your suggestions.
Also, I don't appreciate this mindless bashing on XMPP. All IETF protocols are encouraged (required?) to be fairly secure, which entails things like TLS and SASL. Once you get beyond that, XMPP is not very complex at all. If you have a specific complaint, I'd love to hear it. The XSF is basically as open as the IETF and we're always interested in feedback, but we'd appreciate it if it was constructive.
Why couldn't the spec just include the 'meat'. It's a simple protocol which can be summed up in a page or two. The current spec runs to 55 pages!
Be glad you don't study law! It's practically written in a different language to everyday, pragmatic English. Specs and math papers can descend to similar levels of readability, though RFCs, on the whole, tend to (in comparison) be quite readable IMHO.
Seems a little harsh, - it's written somewhat badly, but the comments about endianness are important - sure, a randomly generated 64-bit integer encoded as big-endian is, entropically speaking, no more useful than it's little-endian brother. It's also useless all by itself. As part of a system though, like a challenge/response system, it's important both ends of the system know how to interpret the data they are dealing with - so this is important.
At that point, defining the fact that you are sending a big-endian 64-bit integer It might seem trivial now that we write everything in Java, but endianness caused all kinds of portability problems in the early internet days when we started making different systems talk to each other, and made simple porting jobs difficult. It's how we ended up with network-byte-order instead of just using long ints and stuff like that - it's very easy to overlook.
In short, being specific about data formats matters.
And yeah, it would suck if they over-complicate things - let's not let that happen - we need simple protocols, but not too simple. It's okay if you can slightly abuse them if it means fast adoption (One can coax HTTP servers to sign into IRC and spam channels - but it's not a big enough problem to warrant redesigning the whole thing, right?)
> " it's important both ends of the system know how to interpret the data they are dealing with - so this is important."
As I say, it's treated, by both sides, as 8 bytes of random data. Never as integers. The endianness here is irrelevant. The spec is going into way more detail than it needs.
What was wrong with requiring a "101 Switching Protocols" response to an "Upgrade" request? Forcing the server to run four full rounds of MD5 just to demonstrate that it actually implements a protocol is absurd. And reordering fields to prove the server is indifferent to ordering belongs in an integration test for the server, not a real client.
When the Internet works, it's thanks to Postel's Law, which is the polar opposite of designing a protocol to maximize the likelihood of failure.
Postel's Law works when everyone follows it, but it's unstable. At some point somebody will be liberal in what he sends and conservative in what he accepts and everyone else will end up working around his bugs forever. This can even lead to a ratcheting effect over time as people use less and less of the protocol to avoid previous bugs.
This leads us to Ruby's Corollary[1]: Be exact in what you send and liberal in what you accept. Since programmers will neither read the spec nor run the test suite, you should build real implementations that exercise every facet of the spec (e.g. randomize anything that doesn't matter). The only way to interoperate with such implementations is to do things more or less correctly.
[1] After Sam Ruby, who inserts test cases into his blog to encourage browsers and feed readers to work better.
His end users deserve better. He's wilfully confronting them with interop failures they aren't in a position to understand, much less do anything about. Testing is a burden which should be borne by developers.
This kind of interop error should be seen and fixed in the earliest development and should never reach users; that's the point of deliberately triggering it.
When it goes over the network it has to be big-endian so both sides agree on the value. That's why we call it "network order".
If the value is random and you send the low byte first and then treat that as the high byte it would work. I can't imagine that ever being useful, but it works as long as both sides agree that that [FE, ED, FA, CE] is 0xFEEDFACE.
If your RNG gives you 0xFEEDFACE you better not send it out as [CE, FA, ED, FE] or you're going to make a mess of things. Host byte order is completely irrelevant.
The endianness here is irrelevant. It's 8 bytes of random data.
My point was, that generating a random 64bit integer and storing it as little endian, would infact work fine. Because the 8 bytes of random data is only used in the context of "8 bytes of random data", and never as "an integer" by both sides.
The spec is just ridiculously overly specific. It's telling us how you can generate 8 bytes of random data. Any programmer implementing it should have a vague idea how to do that.
I completely understand your frustration with the over-specification. Why would they send it over the wire if it was never meant to be used though? Surely the other side is interpreting these bytes somehow and excepts them in a certain order.
[ a bit later ... ]
I decided to check the spec and see for myself what's going on. The part you're talking about, key3, is in fact used later. The bytes may be random but both sides need to know which of the 8 bytes comes first and which comes last.
Let /challenge/ be the concatenation of /number_1/, expressed as
a big-endian 32 bit integer, /number_2/, expressed as a big-
endian 32 bit integer, and the eight bytes of /key_3/ in the
order they were sent on the wire.
If the other side doesn't agree on the order of the bytes in key3 then things are not going to work. Your other complaints may be valid but sometimes this sort of over-specification helps implementers.
I actually spent some time reading that spec yesterday while hunting a bug. I was trying to figure out if maybe we were violating the protocol in some way.
I'm not enough of an expert to weigh in, but the spec did make me chuckle. Super verbose with a dash of paranoia.
This is pretty funny (although gregw has written many longer and more detailed essays about websockets as well):
In the end, we located the bug within our code connecting jetty's websocket support to our message passing system. You can bet that was an adventure to sort out. =)
I'm not sure if it matters that the protocol is complex. A few people will write libraries which expose a simple interface, so the vast majority of people developing with WebSockets wont have to worry about this stuff.
What really matters, is that the protocol is secure, efficient and extensible. If it needs to be more complex in order to meet those criteria, then fine...
After browsing through the spec a little I can't take axod's claims seriously. He's way off the mark saying that endianness of values sent over the network doesn't matter. The fact that they are random bytes is irrelevant, they have meaning even if they are generated randomly.
If you don't understand the point of sending values over the wire in a known order then I'm sorry but I don't trust your ability to properly evaluate the rest of the spec either.
axod: I don't mean this as a personal attack but considering your strong opinions on this I'd expect you to have thought about it more diligently.
16 comments
[ 5.6 ms ] story [ 51.3 ms ] threadIt will catch on because it's all we've got, but we're going to shove yet another mediocre protocol onto the stack of protocols servers need to speak in addition to HTTP.
The people working on this have spent time understanding the problem domain better than I have. But I really hope they've thought this protocol through. Because we'll be stuck with it for a long time.
The protocol is a bit more readable here: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-...
The security protocol does seem a little strange: putting numbers into the fields interspersed with random characters and spaces, taking the numbers and dividing them by the number of space characters, and using 2 fields to make harder. There's a lot of dancing here to ensure that the protocol is implemented correctly.
Also, I don't appreciate this mindless bashing on XMPP. All IETF protocols are encouraged (required?) to be fairly secure, which entails things like TLS and SASL. Once you get beyond that, XMPP is not very complex at all. If you have a specific complaint, I'd love to hear it. The XSF is basically as open as the IETF and we're always interested in feedback, but we'd appreciate it if it was constructive.
Be glad you don't study law! It's practically written in a different language to everyday, pragmatic English. Specs and math papers can descend to similar levels of readability, though RFCs, on the whole, tend to (in comparison) be quite readable IMHO.
At that point, defining the fact that you are sending a big-endian 64-bit integer It might seem trivial now that we write everything in Java, but endianness caused all kinds of portability problems in the early internet days when we started making different systems talk to each other, and made simple porting jobs difficult. It's how we ended up with network-byte-order instead of just using long ints and stuff like that - it's very easy to overlook.
In short, being specific about data formats matters.
And yeah, it would suck if they over-complicate things - let's not let that happen - we need simple protocols, but not too simple. It's okay if you can slightly abuse them if it means fast adoption (One can coax HTTP servers to sign into IRC and spam channels - but it's not a big enough problem to warrant redesigning the whole thing, right?)
As I say, it's treated, by both sides, as 8 bytes of random data. Never as integers. The endianness here is irrelevant. The spec is going into way more detail than it needs.
When the Internet works, it's thanks to Postel's Law, which is the polar opposite of designing a protocol to maximize the likelihood of failure.
This leads us to Ruby's Corollary[1]: Be exact in what you send and liberal in what you accept. Since programmers will neither read the spec nor run the test suite, you should build real implementations that exercise every facet of the spec (e.g. randomize anything that doesn't matter). The only way to interoperate with such implementations is to do things more or less correctly.
[1] After Sam Ruby, who inserts test cases into his blog to encourage browsers and feed readers to work better.
If the value is random and you send the low byte first and then treat that as the high byte it would work. I can't imagine that ever being useful, but it works as long as both sides agree that that [FE, ED, FA, CE] is 0xFEEDFACE.
If your RNG gives you 0xFEEDFACE you better not send it out as [CE, FA, ED, FE] or you're going to make a mess of things. Host byte order is completely irrelevant.
My point was, that generating a random 64bit integer and storing it as little endian, would infact work fine. Because the 8 bytes of random data is only used in the context of "8 bytes of random data", and never as "an integer" by both sides.
The spec is just ridiculously overly specific. It's telling us how you can generate 8 bytes of random data. Any programmer implementing it should have a vague idea how to do that.
[ a bit later ... ]
I decided to check the spec and see for myself what's going on. The part you're talking about, key3, is in fact used later. The bytes may be random but both sides need to know which of the 8 bytes comes first and which comes last.
If the other side doesn't agree on the order of the bytes in key3 then things are not going to work. Your other complaints may be valid but sometimes this sort of over-specification helps implementers.I'm not enough of an expert to weigh in, but the spec did make me chuckle. Super verbose with a dash of paranoia.
This is pretty funny (although gregw has written many longer and more detailed essays about websockets as well):
https://bugs.eclipse.org/bugs/show_bug.cgi?id=294563
In the end, we located the bug within our code connecting jetty's websocket support to our message passing system. You can bet that was an adventure to sort out. =)
What really matters, is that the protocol is secure, efficient and extensible. If it needs to be more complex in order to meet those criteria, then fine...
If you don't understand the point of sending values over the wire in a known order then I'm sorry but I don't trust your ability to properly evaluate the rest of the spec either.
axod: I don't mean this as a personal attack but considering your strong opinions on this I'd expect you to have thought about it more diligently.