Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Preventing form re-submission with HTTP 303 redirects (jonthornton.com)
76 points by heyjonboy on July 21, 2011 | hide | past | favorite | 27 comments


Be really careful with this. While all browsers out there speak http 1.1 by now and thus should support 303 redirects, many proxy servers are still living in http 1.0 land.

A proxy shouldn't care about a status code in the 300 range, but it might (maybe erroring out on "unknown" codes as part of some security feature).

And then there are scripts quickly thrown together using the HTTP libraries of $LANGUAGE. You'd have to check these too if you use them in a context where you'd also use a 303 redirect.

For what it's worth: my app is serving pages to users behind the worst possible collections of both enterprise and personal firewalls that seem to mangle HTTP headers at will. Heck, I even have more than 10% IE 5.5 users on one installation.

That said, ever since 2004 I have never had one instance of a browser or proxy resubmitting a form in response to a 302 redirect. But many instances of where leaving the trodden path, was causing the strangest unexpected breakages due to severely broken client software.

As such, personally, I will stay with what works and what the RFC is admitting to generally work even if it shouldn't, instead of experimenting with semantics for no visible gain what so ever.

Sounding bitter? Once you witness AV software altering Content-Encoding headers without altering the encoding, you too would get bitter :-)


Proxies don't perform the redirect themselves, so they don't need to support it, they just need to pass it through like any other 3xx.

The last UA I saw that didn't support 303 was Netscape 4.

Body of the redirect response should contain a link to the new page. This way even time travellers form '90s will be able to reach the destination page.


This post seems to be based on the belief that everything adheres to the spec. Historically, 302 has always been interpreted like 303 is defined, and never like 302 is defined. For example:

"If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued."

Does the browser you use do that?

As with cookies, developers go with what works, even if it isn't exactly what the spec says.

History aside, it could be that there is now a difference in how 302 and 303 are interpreted by modern browsers, and I would love to see definitive tests. Any volunteers?


I've noticed older versions of Firefox trying to resubmit form data when refreshing after a 302 redirect.

Granted there aren't many people running old versions of Firefox, but why risk it? Even if 302 is generally interpreted like a 303, it's safer to just use a 303.


Safer? The risk is that 303 is misinterpreted, and this risk is why we have always used 302. I'd need evidence before taking a chance based on someone's recollection of an older version of Firefox.

RFC 2616 mentions early misinterpretations; they are why 303 and 307 exist:

"Note: RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location field-value regardless of the original request method. The status codes 303 and 307 have been added for servers that wish to make unambiguously clear which kind of reaction is expected of the client."

Recommending 303 sounds like a great idea, but the spec's description of 303 is what 302 is in practice, and the latest spec (2616) makes note of this reality. Also, consistent support for 303 is not a sure bet:

"Note: Many pre-HTTP/1.1 user agents do not understand the 303 status. When interoperability with such clients is a concern, the 302 status code may be used instead, since most user agents react to a 302 response as described here for 303."

Without evidence, using 303 is the riskier option.


"Note: Many pre-HTTP/1.1 user agents do not understand the 303 status."

The fact is there really aren't any pre-HTTP/1.1 browsers still in use. See: http://serverfault.com/questions/110932/are-there-internet-u...

Given that many web apps these days require javascript and CSS and HTTP/1.1 is over 12 years old, I don't think it's realistic to worry about clients that only support HTTP/1.0.

While 302 works in practice, it's safer to use 303, which works by definition.


The problem is that the browser is not the only client involved. Corporate/country/personal proxies, firewalls and antivirus software all sit in between some servers and clients, some of them still do not handle HTTP/1.1 correctly, and many of them will alter your headers in transit.

As your StackOverflow link mentions, Squid, a widely used proxy, is still only fully implemented for HTTP/1.0.


Corporate/country/personal proxies, firewalls and antivirus software don't perform redirects themselves, so they are irrelevant for status 303 support.

Today all clients that send HTTP/1.0 version support more than HTTP/1.0, e.g. HTTP/1.1 Host header is basically mandatory on the web.

HTTP/1.1 compliance requires some harder things like pipelining support, and full HTTP/1.1 caching proxy has a lot of hairy stuff to deal with (strong/weak cache validators, stitching of partial responses, Vary support, etc.).

You can have quite decent HTTP/1.1 implementation that still doesn't deserve to be called full HTTP/1.1.


Yea, browsers old enough to not send a Host header are pretty much unusable on today's web without a proxy.


Are there any significant drawbacks to using a 303 over a 302 redirect? I ask because I've seen this advice a number of times before - typically on StackOverflow - and I've seen a lot of recommendations to use 302.

One question I found on a cursory search just now[1] asks whether to use 302 or 303. All three answers submitted to the question recommend 302. The key consideration seems to be backwards compatibility with HTTP 1.0 (the 303 response was apparently added for HTTP 1.1), with the understanding that 302s act close enough to 303s that you don't really need to worry about it. Is this a valid concern, or is this simply an old concern that hasn't died even though the context has changed over the years?

[1] http://stackoverflow.com/q/5129076/1588


I think compatibility with 1999 "new" version of HTTP is not a concern any more.

The bigger concern I have is that it allows clients to prompt user and re-send POST after 302 (exactly what the redirect trick is trying to prevent).


I've seen a few people say that 1.0 compatibility can be a factor with some older proxies and similar services. I just wasn't sure how pervasive an issue it actually was.


> Ruby, Python, and PHP default to an HTTP 302 (Temporarily Moved) redirect.

This is very pedantic of me, but as of HTTP 1.1, HTTP 302 is Found, not Temporarily Moved[1].

[1] http://tools.ietf.org/html/rfc2616#section-10.3.3


Django had a ticket for this, and it got closed as wontfix because 302 redirects are known to work fine:

https://code.djangoproject.com/ticket/13277


The sample PHP code can be done with one call to the header function using the second parameter which allows you to set the http response code. Nice article though, learned something new today.


Minor point of correction: the second parameter is a bool asking whether or not to replace a previous similar header. The third parameter allows you to set the HTTP response code.

http://php.net/manual/en/function.header.php


True. Thanks for the correction.


If it makes a difference, Python's urllib handles 301, 303, and 307 with the 302 handler. It also speaks 1.0

http://hg.python.org/cpython/file/0752215f9f91/Lib/urllib.py...


Great article.

This is another reminder that I should really read the HTTP/1.1 spec someday.


Here's the link[1]; get at it.

[1] http://tools.ietf.org/html/rfc2616


[meta whinge] Cursor trails? _Really?_ In 2011? Is this some sort of GeoCities-esque retro fashion thing?


Ha, hadn't thought of it that way, but I can see what you mean. I added it to play around with Canvas, while tying in with the half-tone dot motif in the header.

It could definitely stand to be a bit more subtle, though.


+1 for the trails. Have fun. Do what makes you happy on your own site!


I like the trails. I didn't even notice them until they were pointed out as I don't move my mouse around much.

I also usually put an exit() after redirects, just in case.


I liked fun things like this. Within reason. And this is within reason.


Wikipedia has a good schema explaining this : http://en.wikipedia.org/wiki/Post/Redirect/Get


Can anybody confirm (or deny) that all browsers treat 303 correctly?




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

Search: