ieHTTPHeaders is an amazing extension for Internet Explorer and it's available for free (though the author does accept donations) and it is now an essential part of my web developer toolkit. It's helped me out of a number of tricky situations, allowing a quick peek into the conversations that take place between a browser and a server that often go unnoticed.
In this article we'll cover the following:
- The ieHTTPHeaders utility and how to use it to help you debug problems
- Cookies
- Forms Authentication tickets, user data and encryption
I have been lucky/unlucky [delete as applicable] enough to have been working with web applications long before the days of ASP.NET. Back in the day, web developers would regularly have to get their hands dirty with HTTP plumbing. Many developers today are blissfully unaware of what is happening 'on the wire' and this is entirely understandable with the provisions available in the modern development environment. However, getting to know this beast can be a killer string to your bow. So let's walk through a recent problem I had with Forms Authentication that ieHTTPHeaders and this knowledge helped me solve.
Just recently I was working on a new ASP.NET project that used Forms Authentication. We wanted to use the FormsAuthenticationTicket to encrypt and store an extra piece of data in the cookie. Let's imagine that the application lived in a virual directory called FormsAuthenticationTest directly off the root of the server.
Since we are good boys, we set the forms authentication cookie path appropriately in the web.config so that the cookie is not shared with other applications.
<authentication mode="Forms">
<forms
name=".COOKIENAME"
loginUrl="login.aspx"
path="/FormsAuthentication" />
</authentication> Now let's spice things up a little. Using Forms Authentication is a doddle, but if you want to use some of the more advanced features, such as user data, things get a little more complicated.
Forms Authentication cookies are encrypted using Triple DES to prevent malicious clients from tampering with or reading the cookie. Fantastic! Especially if we can leverage this for another purpose. We can use this secure space to store other little tit-bits of information for re-use later, such as the user's role.
Note: This isn't going to be an ideal solution for everyone and you should assess the security risk of such activities before jumping on this bandwagon. It may suit you, it may not - the choice is yours and so is the responsibility.
The next step is to create our own ticket, using the FormsAuthenticationTicket class:
private string GetUserRole(string username)
{
// imagine we go away to a database here
// to determine the role of the user...
return "Admin";
}
protected void _btnLogin_Click(object sender, EventArgs e)
{
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // The cookie version
_txtName.Text, // The user name
DateTime.Now, // Time of issue
DateTime.Now.AddMinutes(20), // Time of expiry (20 mins)
false, // Should the cookie be persistent?
GetUserRole(_txtName.Text) // Where we put the extra stuff
);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
// Now we need to add the cookie to the response, using the
// cookie name in the web.config
Response.Cookies.Add(
new HttpCookie(FormsAuthentication.FormsCookieName,
encryptedTicket));
// Finally, redirect to the appropriate Url.
Response.Redirect(FormsAuthentication.GetRedirectUrl(_txtName.Text, false));
} You should find that this works a treat, it did for me. Until I tried to logout, which should be even easier:
protected void _btnLogout_Click(object sender, EventArgs e)
{
FormsAuthentication.SignOut();
} Sure, clicking the Logout button took us to the login screen as expected, but if I navigated the rest of the site it was clear that I was still logged in - the cookie must still exist!?
I smelled a fish. And fish and cookies just do not go.
Time to have a look at what ASP.NET is saying to my browser. If you haven't installed ieHTTPHeaders yet, now is probably a good time to do so.
Once installed, it's easy-peasy to use. Open Internet Explore and go to
View > Explorer Bar > ieHTTPHeaders to display the frame in which you'll see the output, as shown below. Now start surfing the web and you'll see a plethora of headers streaming through the window.
Note: After install you may have to close all IE windows before the plug-in appears. Failing that, try a reboot.
Let's look in more detail at the exchange between the browser and the web application that seems to be serving up dodgy cookies.
I've copied the output from ieHTTPHeaders into the table below with an explanation on the right giving a brief summary of what it all means.
HTTP Header (interesting bits in bold) |
What's going on? |
GET /FormsAuthenticationTest/default. aspx HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: en-gb
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50215)
Host: localhost
Connection: Keep-Alive
|
This is the browser requesting the default.aspx page at the root of the web application.
Note that the browser also tells the server what it is (User-Agent), what file types it accepts and much more.
|
HTTP/1.1 302 Found
Server: Microsoft-IIS/5.1
Date: Sat, 15 Oct 2005 15:22:18 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50215
Location: /FormsAuthenticationTest/login.aspx ?ReturnUrl=%2fFormsAuthenticationTest %2fdefault.aspx
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 204
|
The server replies, with a 302 response. This is a "Redirect" instruction to the browser. "This isn't the page you're looking for. Move along. Try login.aspx" |
GET /FormsAuthenticationTest/login.aspx ?ReturnUrl=%2fFormsAuthenticationTest %2fdefault. aspx HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: en-gb
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50215)
Host: localhost
Connection: Keep-Alive
|
The browser, being a nice browser, does what it's told and requests the specified page. |
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Sat, 15 Oct 2005 15:22:18 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50215
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 726
|
"Oh, you want the login page? No problem, Here you go!" |
POST /FormsAuthenticationTest/login.aspx ?ReturnUrl= %2fFormsAuthenticationTest%2fdefault.aspx HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://localhost/ FormsAuthenticationTest/login.aspx? ReturnUrl= %2fFormsAuthenticationTest %2fdefault.aspx
Accept-Language: en-gb
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50215)
Host: localhost
Content-Length: 114
Connection: Keep-Alive
Cache-Control: no-cache
__VIEWSTATE=%2FwEPDw...snip...kYLBz4& _txtName=Josh& _txtPassword=password& _btnLogin=Login |
Now, the user has entered their credentials and posted it up to the server. You can see the body of the post emboldened at the bottom of the page.
This post would cause the _btnLogin_Click event above to execute. |
HTTP/1.1 100 Continue
Server: Microsoft-IIS/5.1
Date: Sat, 15 Oct 2005 15:30:40 GMT
X-Powered-By: ASP.NET |
You'll see a lot of these. It's essentially the server saying ";OK, got your request. Just hang on a minute and I'll get you a response". |
HTTP/1.1 302 Found
Server: Microsoft-IIS/5.1
Date: Sat, 15 Oct 2005 15:30:40 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50215
Location: /FormsAuthenticationTest/default.aspx
Set-Cookie: .ASPXAUTH=A90B1E...snip...69C5E9; path=/
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 154 |
Right, now we're on the money!
Look! The server is trying to set the encrypted authentication cookie using the Set-Cookie command. Also, as expected, the server is redirecting us back to our original destination.
Note the ";path=/"; section of the Set-Cookie directive. Wait a minute - there's something wrong there! We'll discuss what later. |
GET /FormsAuthenticationTest/default.aspx HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Referer: http://localhost/ FormsAuthenticationTest/login.aspx ?ReturnUrl=%2fFormsAuthenticationTest %2fdefault.aspx
Accept-Language: en-gb
Cookie: .ASPXAUTH=A90PXI...snip...832RE9
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50215)
Host: localhost
Connection: Keep-Alive
Cache-Control: no-cache
|
Following instructions again, the browser requests the designated page and look!
The browser has remembered our cookie and will now send it back to us every time. Yeah! |
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Sat, 15 Oct 2005 15:30:40 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50215
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 962
|
Finally we get to our original page. The server delivers the default.aspx page with a cheerful 200 OK Code. |
It always amazes me how many exchanges the client and server have in a simple Forms Authentication scenario. This is nothing to worry about - it all happens very quickly and your users will be blissfully ignorant.
So, what went wrong when we tried to logout later? Lets look at the header returned from the server after the logout request was issued.
HTTP Header |
What's going on? |
HTTP/1.1 302 Found
Server: Microsoft-IIS/5.1
Date: Sat, 15 Oct 2005 16:05:58 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50215
Location: /FormsAuthenticationTest/login.aspx ?ReturnUrl=%2fFormsAuthenticationTest %2fDefault.aspx
Set-Cookie: .ASPXAUTH=; expires=Mon, 11-Oct-1999 23:00:00 GMT; path=/FormsAuthenticationTest; HttpOnly
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 1159 |
The server is re-issuing the Set-Cookie command. But this time the cookie is empty and set to expire back in 1999. This is how servers tell browsers to delete a cookie.Note that the cookie path is "/FormsAuthenticationTest". Uh-oh. |
The clue to our problem was in the server's original Set-Cookie instruction. We have specified in the web.config that the cookie path should be "/FormsAuthenticationTest" but when the original cookie is issued it is issued to the root path "/". Why?
Simple! Because we're issuing the cookie ourselves. Remember this piece of code in our login routine?
Response.Cookies.Add(
new HttpCookie(FormsAuthentication.FormsCookieName,
encryptedTicket)); It seems obvious now, but because we're taking responsibility for issuing the cookie away from the FormsAuthentication class, we must set the cookie path ourselves otherwise the default root path is assumed. When the cookie is later deleted by
FormsAuthentication.SignOut(), it targets a cookie with a different path and the removal doesn't go quite as expected thus logout fails. Eureka! And the fix?
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName, encryptedTicket);
// get the path from config
cookie.Path = FormsAuthentication.FormsCookiePath;
Response.Cookies.Add(cookie); Now I just need to workout how to get the cookie path from the authentication section in web.config to avoid having to specify it twice :o)
One last tip before we part company: When using ieHTTPHeaders you may find it useful to disable images in your browser, this will significantly reduce the amount of 'noise' you have to wade through.
Good luck and enjoy!
Josh

Post By
Josh Twist
12:22 PM
16 Nov 2005
» Next Post:
XHTML in .NET 2.0
« Previous Post:
SQL Profiler with .NET
Comments are closed for this post.
Posted by
charlie arehart
@
17 Aug 2006
4:12 PM
Thanks for the nice intro to the tool. Every other entry i was finding while searching just left it as "an add in to the IE explorer toolbar". Yours was the first I saw to explain that this mean view>explorer bar. I had been looking for something on the toolbar.
If I may say so, Fiddler (free, from Microsoft, at
http://www.fiddlertool.com/) really does a superior job of organizing the information that iehttpheaders just dumps at the bottom of the screen. There's a whole lot more information there about it than at Mr Blunck's spartan site--though as a free tool from one person it's understandable.
Back to my first point, Fiddler also installs itself as an icon on the IE toolbar, which is nice. But for many more reason, I will recommend folks check it out, too.
on the other hand, does indeed . Better still, it
Posted by
charlie arehart
@
17 Aug 2006
4:16 PM
Pardon the last lines there. Leftover from some editing of the comment and I forgot to delete them. Also, in case it's not clear, I meant to say "there's a whole lot more info about Fiddler at its site than there is about ieHTTPheaders at Mr. Blunck's site."
Posted by
Josh
@
18 Aug 2006
12:22 AM
Hi Charlie,
Thanks for getting in touch. I'm a big advocate of Fiddler too and have linked to it in a few posts. However, I do love the speed and ease with which I can flick ieHTTPHeaders on to just have a nosy at what's going on.
I often use it if I want to see what platform a server is running on. Firing up fiddler just feels a bit more 'intrusive' so I save it for those hardcore debugging jobs.
Posted by
roger
@
25 Aug 2008
7:01 AM
nice
Posted by
roger
@
25 Aug 2008
7:01 AM
nice
Posted by
rerer
@
25 Aug 2008
7:02 AM
nice