HTTP POST Fails for Anonymous Authentication

Question:

I have ASP that receives a POST, displays the parameters and performs additional work. Authentication was anonymous (IUSR_<machine>) and also Integrated Windows.

Then I turned off Integrated auth (we can discuss reasons for this later). I am still able to process the page, but evidently there is NO POST data. ASP code does run, I can see Response.Write output, but all POST params are empty.

I then changed the IIS authentication of anonymous user account to a local system user account (new user, new password), still no luck. Finally I tried changing to local Administrator, still no luck.

Logfiles give me no clue - IIS seems to be happy that it correctly processed the file.

Is there any hope for me?

Answer:

We are just talking about software; of course there is hope. Reinstallation is always an option. :-) It's not like water, fire, bullets, or outer-space where you only get one chance and mistakes are a bit more costly...

I believe you are observing the behavior described in KB 251404. Classic mixed authentication conflict with browser-side optimization. Basically, whenever you POST with Internet Explorer to a URL that uses anonymous authentication AND the browser has visited other NTLM authenticated URLs from that website, you will encounter this behavior.

One of the most common way for people to run into this situation is with custom authentication. They usually enable custom authentication on all their webpages which redirect unauthenticated requests to a /logon.asp URL which uses anonymous authentication to present a FORM for users to login with. However, they find that on the POST, the username/password are NOT given to /logon.asp and the custom authentication fails.

The ways to fix this? Either:

  1. Disable the client-side optimization (Registry Key mentioned in the KB Article)
  2. Use an uniform authentication protocol on the server (which has other benefits - Secure Single Sign On pretty much requires uniform authentication protocol because any other mechanism must be insecure, as I detail why in this blog entry).

Why does this happen?

The underlying cause of this behavior is an optimization in Internet Explorer. Why does this apparently broken optimization exist?

Well, let's first look at the classic POST request sequence to an authenticated URL:

  1. Client makes anonymous POST request with 1GB entity body to a URL which requires authentication on the server.
  2. Server rejects the POST with a 401 response and indicates with WWW-Authenticate: headers the authentication protocols the client to use.
  3. Client makes another POST request with 1 GB entity body to the URL in accordance to the authentication protocol, negotiates authentication (this may involve additional requests/responses, depending on protocol), and eventually the URL is executed.

The reason that the initial request is anonymous is because HTTP clients are not clairvoyant - they cannot know that the server requires authentication prior to making that first request - so making the initial request anonymously makes sense since the server will reject with a 401 response if authentication is required.

After the HTTP client receives the WWW-authenticate headers, it knows what authentication protocols are required by the server (at least, it thinks... this is where mixed authentication foils the optimization), so it can attempt some optimization techniques. For example:

  • If the client negotiated Basic authentication, it knows that every subsequent request must have the Authorization: header. Thus, step #1 is not needed and the client should just perform step #3 with both the entity body and the necessary Authorization: header.
  • If the client negotiated NTLM authentication, it knows that the second leg of the NTLM handshake during step #3 is a obligatory 401.1 response, so sending entity body for that leg of the handshake is not useful. Thus, a reasonable optimization is to NOT send any entity body until the final leg of the handshake, when the URL is finally executed.

These optimizations make a lot of sense because sending 1GB entity body during the authentication handshake is simply a waste of bandwidth, especially for a request that will be rejected as a part of the authentication protocol. In the old days of modems, the optimization can easily save hours off of an authenticated POST. In today's broadband environment, it still shaves off minutes.

In fact, optimal websites today will even truncate their 401.1 and 401.2 custom error responses to further reduce bandwidth usage during anticipated authentication.

How does the Optimization fail?

Now, the astute reader should realize that this optimization fails for a server in a mixed authentication configuration. Here's how it fails:

  • Suppose the HTTP Client encounters a WWW-Authenticate: NTLM header returned by the server during an earlier request. It now THINKS this server requires NTLM authentication.
  • Later on, the HTTP Client is told to POST a FORM to a URL on this server. Unknown to the client, this URL only requires Anonymous Authentication.
  • Since the HTTP Client thinks the server requires NTLM Authentication (that's what the earlier request told it), it chooses to NOT send the entity body for what it anticipates to be the second leg of the NTLM handshake.
  • However, since the URL only requires Anonymous Authentication, no NTLM handshake ever takes place. Thus, the URL executes as-is... without the entity body.
  • Since the entity body contains all FORM parameters, this sequence of events effectively loses all of them when the URL executes

And why does it work when the URL has Integrated Authentication enabled? Well, the NTLM handshake now takes place and "consumes" this optimized request, and on the final leg of the handshake the entity body is dutifully POSTed by the HTTP Client... and since the handshake completes successfully, the URL executes and sees the POSTed entity body. Everything works.

//David