The Several Million Dollar Bug
jacquesmattheij.com
jacquesmattheij.com
while pending_requests():
send_request()
read_response()
But what send_request and read_response are doing is putting data on the OS's outbound queue and then attempting to get data from the inbound queue. If the data is already in the inbound queue before the request is put on the outbound queue it doesn't matter - the browser is not aware of this fact. So long as the "responses" don't come in faster than the browser is sending requests and causing the queue to overfill, and so long as the responses send out come in the order the browser is sending requests this technique will work. In general this is just an "optimistic strategy".In my mind the fact it works seems like dumb luck and I would never have thought to try it -- all of which is pretty depressing seeing as how evidently it made you lots of money, which is certainly something I could do with :) In hindsight, it makes perfect sense to exploit a simple solution with low implementation costs even if it has an unknown lifespan or potential risks - if it breaks, you're no worse off than you were before (well maybe not if your clients have come to depend on it and you don't have a backup), if it doesn't, great!
It sounds like it'd be hard to implement and for what benefit?
It's of course totally possible for one to make a client that reads responses regardless of whether it send a request, but that's rather silly as giving up flow control like that immediately opens your application up to a DoS attack. (Of course just because it's silly doesn't mean no-one does it!)
I wonder if that's really how browers work or if they employ an array of open connections that are periodically polled for responses to outstanding requests.
Obviously, responding to something that wasn't requested is a bad idea.
Flow control only works for large responses (which is good, because that is at least one resource that you can protect), makes you wonder what you could do with multiple answers small enough to fit in the same window and if that would allow you to identify HTTP implementations that have taken 'asynchronous' one step too far.
So, presumably if someone requests anything from your site you can keep bombarding their browser with unrequested content that will get queued. As jacquesm indicates having an array of connections with reserved queues would avoid this blocking requested content.
So effectively all that can happen is a website can DoS the connection to itself.
(Yes, an attacker can try to initiate many many TCP connections. This uses much fewer resources than an actual HTTP session would but can still be an effective DoS attack. This is known as a SYN flood.)
So you could follow up a HTTP response for http://empty.website.with.no.other.files.to.request.com/ with a HTTP response containing malicious javacript. When the user then tries to view a different website (say their facebook page), they get 'served' your javascript that is now running under the context of the new site. Cookie stealing and other attacks could be run.
In practice it would be unlikely to happen. If the client doesn't read the 2nd request then it is likely to be sitting in a network buffer assigned to the first connection, which will probably be thrown away when it comes to open a connection to the new site.
"Early" responses just sit in this buffer until the application (the browser) gets around to reading them; presumably after it's finished sending the request. The size of this buffer is advertised by the client's OS to the server's OS. A well-behaved server will stop sending data when the client's buffer is full. If the server is not well-behaved, the client just drops future packets (which the server will re-send later). The client is not aware of any of this.
If on the other hand, the server sends a wholly unsolicited response, well, it will still sit in the buffer if the client only reads data after sending a request. But say the client is designed to process incoming responses regardless of whether it sent a request, sure, there could be an exploit there, but that's no different from any other buggy network code.
ISTR some webcam software that would fall back to a java applet (that would parse the multipart MIME) on IE. Anything is preferable to that though!
And there always was a way, even if sometimes it required some - for want of a better word ;) - unorthodox methods.
>My main occupations are being owner/operator of ww.com, which pioneered streaming webcam technology, and working as a consultant to do technical due diligence.
Reading the article, at first I assumed he was someone who worked on an early browser or something, then maybe a hardware webcam manufacturer. I assume that he's just not used to people showing up at his blog with no context about who he is, so there you go.
Thank you for the feedback.
But this isn't really a "bug" per se; the TCP model is a stream is a stream is a stream. There's no notion of time, packets, or correlation between streams. So browsers (and the OS) are acting only as they can; by treating a TCP connection as two independent streams.
(Though, how could it be otherwise? Assume HTTP over SCTP (sequenced packets). We can't require, or even allow, HTTP servers to ignore response packets that arrive "too early", since it's possible that observers of the client (e.g. Wireshark) may not observe the exact same timing, which would lead to divergent interpretations of the conversation.)
Amazon does this too. Upload APIs will return 4xx errors well before the body is uploaded in the event there's an issue with the headers. Not that (a) most HTTP clients pay attention to this, or (b) they can do anything about it without closing and reopening the connection.
So will those ISPs also not pass Amazon's upload APIs responses? That would be pretty sloppy!
Years ago, IDS and IPS were separate products, where IDS was the earlier, more primitive version of the other. Now-a-days, you are buying an IPS, which is run either in alerting mode (operating like an IDS) or in "shunning" mode, where the device tracks some defensive action (such as dropping traffic, bandwidth throttling, blacking the IP for a fixed period of time, etc).
"Shunning" mode can be dangerous, since you are essentially building in a feature to "Deny service to X for Y amount of time" into your network.
Attackers can spoof attacks to deliberately trigger the shunning of legitimate users. Because of this, it is less common to see an IDS/IPS with shunning enabled in production. It depends on where "Access to service for legitimate users" and "stopping and possibly hurting attackers" fall on the priorities list.
I don't think it is possible to respond early in case of a successful upload, after all, that means the upload can still fail for a variety of reasons. Success indicates that you can move to the next state, and an 'early success' might still turn into a late failure.
What can happen is:
* Client starts to send HTTP request (e.g. POSTing a file). The file is large, so it will take a while to upload.
* Server spots that the user isn't allowed to upload the file and immediately returns a 4xx error of some kind.
* Server then thinks all is finished, closes connection.
* Client, still sending the file, gets an error as the write() fails. Complains about the broken connection to the user but never notices the actual HTTP response.
Many HTTP clients are written in a simple 'send my request, then (and only then) read the response'. They don't react well to getting an early error message. Often you have to work around this by not closing the connection to the client, and continuing to slurp up any further data received.
We had a vendor who's product did this. Everything worked except one feature (the main feature) and a quick glance at the firewall logs showed 'malformed tcp packet' flooding the console.
It was a simple thing to disable (from just their appliance, not the whole network), but I still found it odd that they did that.
It just doesn't make a lot of sense doing the above. Especially because there's a fundamental race condition here: there is no way to distinguish between data that's in-flight but not received prior to the browser issuing the request, and data that was generated after the remote peer read the browser's request.
Erlang TCP connections can be configured for asynchronous receive: any incoming data is delivered as a message to a given process, which usually immediately acts on it. Say this process has not yet sent a request; it's not unreasonable to just drop the incoming data.
Of course, I would consider such behavior non-conforming, for the reasons you point out. Time isn't really defined in a TCP stream.
Better is to utilize the flow control Erlang provides for asynchronous receive, but this is extra effort so it's plausible a naive implementation would miss this.
The only concrete example I can recall is that Suck.com used this to have an animated logo at the top of their page. (I think this predated the Java applet version that you see on the Internet Archive...)
Combining it with dynamically generated DNS names might be a nice "content accelerator" add-on for CDNs, etc.
ie: a page uses resources, each of which has a unique url.
You have custom infrastructure (that sits in front of a normal website) which dynamically generates a new subdomain for each resource, and replaces the resource urls with the new urls (using the subdomain).
At the top of the page (or ideally on the previous page) you include some zero-length resources with the same MIME-type as the resources you want to serve.
The browser requests these resources, and as soon as you have the connection open you reply with the zero length resource and then the actual resource you want to serve.
Subsequently the browser requests the actual resource, and finds it already waiting.
The unique hostnames are needed to allow you predict which resource will be requested.
(This was probably patentable until I wrote it all out, too ;))
Strictly speaking extra bytes sent past the end of the response to the current request (or before even any request has been sent) is a protocol violation but I'm really not complaining about this one, after all, that line in the spec does not actually specify the timing. We all just read between the lines to see what we expect to see: ping ... pong.
In most cases, even if the web server knows that a specific page contains images, it does not know if the browser is actually going to request those images. What if it is a bot? What if the user cancels? What if they have disabled image downloads in that browser? What if they have the images and other secondary files cached?
I do think it is worthwhile to consider such things for your individual needs, but most use cases won't change the standard request/response mechanism.
For instance, if a bot is pretending to be a Chrome browser, you'd think it was a regular client, but in fact it was not. But that's the bot's fault, not your implementation.
It's your implementation that breaks the protocol spec, not the bot, so it is still your fault.
I get that if the browser sends a GET request for a picture, it's possible that the server already answered. But what happens afterwards?
Is the connection closed? Or does the server send another JPG again?
multipart-mime / content-replace only worked with Netscape, not with IE.
What else is needed for this solution?
Is there a index.html page with a <img>-tag and some javascript that requests the picture again every time the image was loaded?
I'd rather not post the link in the thread because the poor people sending out the stream would not be able to satisfy even a small portion of the kind of volume that HN can direct to a site in an eyeblink.
If you get lucky it will work, but if you're unlucky then you'll be sending out the wrong payloads on all but the first request.
The only reason this trick worked for the webcam is because it knows ahead of time what kind of request will come (the request for the next frame). That's why it can anticipate.
That's the problem right there. Right off the bat I don't see how to get around that one.
At that point you might as well just inline the css and javascript.
[0] http://stackoverflow.com/questions/1806228/browser-support-o...
But how are you going to use UDP to send images to a browser without using a plug-in or an applet? The whole idea was to remain 'compatible' (for small values of compatible) with HTTP, which more or less guaranteed delivery.
UDP wouldn't make it through most firewalls and would make all kinds of assumptions about port forwarding and so on besides that fact that browsers simply do not expect content to arrive via UDP.