The Cookie Hack: using mod_perl to make IE7 think you're not using Basic Auth (even though you are)
You may have heard that the forthcoming MSIE 7 web browser made some "enhancements" for Basic Authentication (warning or optionally disallowing it unless used over SSL). You could buy a certificate or try converting to digest auth or you could implement a cookie hack. It goes something like this (assuming you're running Apache 1.3 with mod_perl):
- Create an ErrorDocument 401 with an external redirect to an HTML page with a login form. Normally it's a bad idea to put external redirects on your 401 documents (because it turns them into 302s [or is it 301s?]). Anyway, it's still a bad idea but that's OK because this whole thing is a bad idea.
Create a "login form" page that looks something like this:
<script> window.onload = function () { var F = document.forms['login']; F.onsubmit = function () { document.cookie = "auth=" + btoa(F['username'].value + ':' + F['password'].value); location.href = 'http://example.net/URL/THAT/REQUIRES/LOGIN'; return false; // probably not necessary }; }; </script> <form name="login"> <input type="text" name="username"> <input type="password" name="password"> <input type="submit" value="log in"> </form>The above uses the little-known btoa() function. It encodes to base64. Too bad MSIE doesn't support it. You'll need to find or write your own base64 encoder. But then you've just screwed all the browsers that aren't running javascript. So then you write yourself some server-side CGI/PHP/ASP/JSP code that sets the cookie instead. Whatever you do, the result is a cookie called "auth" with a value that should look just like the right side of a typical "Authorization: Basic" HTTP header.
Here's the fun hack part. Write a mod_perl HeaderParserHandler that does something like this:
use Apache::Constants 'DECLINED'; sub handler { my $r = shift; my $h = $r->headers_in(); return DECLINED if $h->{Authorization}; if (my $c = $h->{Cookie}) { for (split /\s*,\s*/, $c) { if (m{\bauth=([a-zA-Z\d\+/]+)}) { $h->{Authorization} = "Basic $1"; last; } } } DECLINED; }Now when Apache sees one of our "auth" cookies coming in, we make it think that you actually sent an "Authorization" header. If it's correct, it lets you in. If it's wrong, you get a 401 and get redirected back to your login page.
It's just as "secure" as always (that is, not at all) but it does have some advantages over basic auth:
- Delete the cookie, and you're logged out. No need for a browser shutdown as in basic
- Add an expiration date to the cookie, and your login "session" can survive a browser shutdown
- Set the domain of the cookie to .example.com and suddenly you don't have to maintain separate logins for http://www.example.com/ and http://example.com/ perhaps even https://www.example.com/
If you really want to run with this, you could work around the insecurity by encrypting the the username and password on the client side and expanding the mod_perl handler to decrypt before setting up the fake auth header. You'll have to figure out how to pass the key securely.