Fighting RFCs with RFCs
Google’s recently released Web Accelerator apparently has some scary side-effects. It’s been spotted pre-loading links in password-protected applications, which can amount to clicking on every “delete this” link — bypassing even the JavaScript prompt you carefully added to give people the chance to think twice.
"Aah," I hear you cry, "but RFC 2616 clearly states that you shouldn’t perform state changing operations with a GET or HEAD method!"
In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval.
I’ll see your RFC 2616 and raise you an RFC 2119:
SHOULD NOT This phrase, or the phrase “NOT RECOMMENDED” mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behavior described with this label.
Hiding your dangerous delete links behind an authentication scheme is a perfectly acceptable compromise. Web Accelerator is B.A.D.
Update: Be sure to read the excellent discussion brewing in the comments. Hiding behind authentication may not be as acceptable a compromise as I had first thought.
Update 2: If you haven’t been following the comments, I’ve had a change of heart. Even in the absence of Web Accelerator, hiding behind authentication leaves your application open to some very nasty security vulnerabilities (malicious pages can piggy-back your session and cause havoc making dangerous GET calls). I still think the RFC language covers people who thought long and hard before implementing a dangerous GET, but if you haven’t thought about security and accelerating caching proxies such as Web Accelerator you haven’t been thinking hard enough.
Update 3: So, it turns out using POST is no defence at all against CSRF attacks. I’ve been learning a whole bunch of interesting stuff this evening.
Adam Michela - 6th May 2005 20:46 - #
Matt Brubeck - 6th May 2005 20:47 - #
It's really not a "perfectly acceptable compromise," Simon. Just because something is sitting behind an authentication scheme does not mean that the semantics of "SHOULD NOT" change. At the time the decision was made to use GET in a non-safe/non-idemponent manner, the "full implications" were different. Now we have services that are using HTTP for what it's worth and we need to reconsider the implications. Accelerated caching proxies are not limited to google. I can't even use the damn thing and I probably wouldn't if I could but the concept is legitimate given some basic adherence to best practices. Attempting GET/HEAD requests on links pulled from a page is something that could be extremely useful in many scenarios.
What I've been trying to figure out is whether there is any guarantee that a link found in an a/href attribute is guaranteed to be describing a GETable link. I can't think of any case where this wouldn't be the case but it occurs to me that blindly assuming that any link you come across should be resolved with GET is a bad assumption.
I think both Google and the rampant misuse of GET in non-safe/non-idempotent situations are serious issues. Everyone's wrong here. Please don't encourage this blatant misuse of a very fundamental aspect of web interoperability.
Ryan Tomayko - 6th May 2005 21:00 - #
Simon Willison - 6th May 2005 21:05 - #
The full implications, in this case, are that you can't assume GET is a deliberate link activation by a user, so even if you break the SHOULD, it would be insane to do so for destructive actions like deletes.
RFC 2616 also says:
It's difficult to think of a scenario where it's acceptable to change state even when the user hasn't requested it, but that doesn't mean you can simply disregard the SHOULD safely.
People are talking about this as if it's a new problem. I remember similar applications in the mid-90s that pre-fetched linked pages, and they uncovered similar problems.
If a web developer ignores the SHOULD in the face of historical precedents (and, IMO, common sense), then they have forfeited any right to complain when it breaks, and should take responsibility instead of pointing the finger at the application exposing the error.
Jim - 6th May 2005 21:47 - #
Jim and Ryan: you both make excellent arguments. I've used delete links in the past knowing full well that they're "bad", but I'd always assumed that authenticated web applications could get away with that kind of abuse without any harmful side effects. I'm obviously not alone - support for this kind of thing is built in to Rails (the framework has a :confirm attribute for easily adding JavaScript confirmation to dangerous links) and is evident in a huge number of web applications.
The thing is, we're not doing this out of ignorance. GET links have a number of genuine advantages over POST buttons from a usability point of view - a classic example is that I can bulk delete items with GET links by opening each link in turn in a background tab. I'm convinced now that password protected web applications are not the special case I had thought they were, but it's a tough pill to swallow for the open-in-new-tab reason alone. Maybe Firefox needs a "POST this form in a new tab in the background" ability.
Simon Willison - 6th May 2005 21:56 - #
Matt Brubeck - 6th May 2005 22:16 - #
That sounds like a shortcoming of the web application that is covered up by a feature of the UA, to be honest. Perhaps understandable when things like GWA were niche products, but not now a big name like Google is doing it.
Wouldn't that bulk deletion be more useful if, say, it was implemented as buttons to the side of each item, that activated XMLHttpRequest to delete while staying in the same place on the same page, simultaneously removing the item from the DOM?
Obviously it's more work than a set of links, but that seems to me to be a corner that people felt safe cutting until somebody highlighted the problem by doing something perfectly reasonable and according to spec, but nevertheless reacts badly with this deviation from spec.
I've actually wanted this for a long time, for various reasons.
Jim - 6th May 2005 22:17 - #
Can't you do this as easily for POSTs: with hidden frames that do posts automtically (onload)?
Julien Couvreur - 6th May 2005 22:26 - #
Julien: indeed you can. I just posted about this to the Rails mailing list. Since their web archive isn't working at the moment, here's my email in full:
By "ealier argument", I refer to a message in which I suggested that POST forms had a security advantage over GET in guarding against the malicious third party web page attack.Simon Willison - 6th May 2005 23:03 - #
And session hijacking...This is not the only security threat in web applications (cross site scripting, SQL injections, etc) and it is not applicable in every situation. Can you use GWA on your company's internal Project Manager? Session hijacking is not an issue in this situation, yet the same mayhem is unleashed upon your internal web app as is unleashed on a public, authentication based web app like Backpack.
I think the web is changing and GWA didn't take that into account. Sure, these same types of scenarios (delete links) have been available since the dawn of the web, but how available have they been to Joe Sixpack? Google may have followed the RFC but where does that leave the end users of these new, popular apps? A bit out of luck, it seems.
Chris - 6th May 2005 23:03 - #
Also, I've seen this question floating around a bit and am unsure if everyone knows the answer. Checking the referring site is NOT safe! The referring site URL is sent to the sever in the HTTP header. This means it can easily be spoofed by someone who knows what they're doing. Chris Shiflett has some words on the subject.
Chris - 6th May 2005 23:09 - #
Referrer spoofing for CSRF attacks (that's apparently what this kind of thing is called) is actually a lot harder than you would think - CSRF attacks only work because they trick a user's browser which is already logged in in to making a malicious GET or POST request, and there's no way for a malicious page to modify the referrer (at least not without using XMLHttpRequest, which wouldn't work due to the same-domain security policy).
That said, referrer checking is still a bad idea because it's relatively common for security-sensitive users to disable referrers in their browser - or for companies to run proxies that strip referrers from ALL outgoing HTTP traffic.
Simon Willison - 6th May 2005 23:18 - #
That's what I think too. I didn't know that these hidden form fields where called "formkeys" though. Good to have a name to refer to a common pattern (although it applies beyond forms).
I hope that as frameworks start including formkey support as discussed above, not all pages and forms will get protected that way ("The more security, the better"). The W3C guideline should be enough for most of the GET vs. POST issues (so that crawlers and GWA wouldn't screw stuff by accident). But formkeys should really only be used on forms that require some security.
Reset password pages and delete email forms should be protected with formkeys, but I hope not all forms will get locked. Otherwise, un-official cross-site integration functionalities (bookmarklet, Greasemonkey user scripts, ...) and other user-driven innovations are going to suffer big time.
Julien Couvreur - 6th May 2005 23:33 - #
Simon Willison - 6th May 2005 23:35 - #
My point was that if mass deletion is a common use-case of a particular web application, then the web application should make it easy to do so without falling back on a workaround, particularly one that is only available in some browsers.
Having to open a bunch of extraneous tabs just to delete multiple items efficiently doesn't sound like good design to me. It sounds like a workaround that only expert users would think of.
I remember these types of web accelerators were quite popular in demo form on magazine cover disks back when everybody was on dialup. They certainly weren't uncommon.
Jim - 6th May 2005 23:39 - #
Matt - 7th May 2005 00:14 - #
Actually, I have a couple of Greasemonkey scripts that cause POSTs to other domains. If these other domains were to reject the POST because the formkey is missing, these script are dead. And there is no formkey in the current page that can be scraped in the DOM...
Julien Couvreur - 7th May 2005 00:19 - #
Simon Willison - 7th May 2005 00:34 - #
http://www.sencer.de/article/92/get-considered-har mful-sometimes
And it was again Jesse, that made me aware there is more to it:
http://www.sencer.de/article/122/securing-forms-wi th-post-is-not-enough
Lots of sites/applications still get this wrong.
Sencer - 7th May 2005 00:41 - #
I didn't think of using GM_xmlhttpRequest. It's a good workaround if needed.
There is still a problem for bookmarklets though (I have a bookmarklet for bookmarking pages, using a hidden popup and a post), but GM is kind of replacing bookmarklets anyways...
Julien Couvreur - 7th May 2005 05:37 - #
Nik Cubrilovic - 7th May 2005 07:36 - #
Simon, I don't understand why you need to have get links for deletion and open them in multiple tabs.
If you have a single page with multiple items that can be deleted on it, why aren't there checkboxes for each item with a delete submission that deletes all checked (pending confirmation, presumably)?
Lach - 9th May 2005 03:07 - #
Ren - 11th May 2005 15:20 - #
I think that alot of people here are getting stuck on the details and are missing the big picture.
The Google Web Accelerator is a lousy idea for a litany of other reasons. Not only can it screw up websites, but it is one of the most blatant privacy violations on the web and makes it difficult for webmasters to know who is visting what parts of their website.
Brian Duffy - 12th May 2005 14:30 - #
Ren - 12th May 2005 18:38 - #
Safari can do this (splat-click the submit button). I never realised Firefox can't until I read your post. It's a bit of a contrived case though, surely?
Rupert Jabelman - 14th May 2005 01:34 - #
Brian: How much worse is Google Web Accelerator than (to name two examples) Durham University forcing all internal users to surf via a Squid caching proxy, or a school using Microsoft's ISA Server to ensure that all users are using a caching, prefetching proxy for their web access?
My guess is that the only complaint here is one of scale (more people use GWA than are stuck behind a proxy), to which I'd respond that unlike people stuck behind a proxy, GWA users have chosen to use GWA; most proxy users are forced to use the caching proxy.
Simon Farnsworth - 31st May 2005 17:18 - #