Response: Django with HTTP Authentication

30 Jun 2006

NOTE: I have not seen Scott’s code. This means that my conclusions about his method could be wrong, depending on whether or not he has already dealt with the issues.

In a recent post by Scott Paul Robertson on his blog titled, Django with HTTP Authentication, he builds a workaround for Django’s lack of a proper hook to use the authentication system that he needs/wants to use (BTW, LDAP is a good choice and a secure one). I feel for you man, as I’ve “been there, done that and didn’t even get a lousy T-shirt!”

Since Django can not deal with LDAP on it’s own, he decided to use HTTP Authentication and tie Apache (or so it appears) to the LDAP store. Of course, his app still needs to know, at the application level, that a valid authentication is present, which user it is and perhaps some other information.

Unfortunately, this approach could lead to some little security problems.

Again, I don’t know if Scott has already worked around these or not, but I felt it would be good to publicly discuss the possibilities. For all I know, he already has this licked:

  1. There is no way for the server to revoke nor enforce revocation of authentication once credentials have been accepted.
  2. By having code rely on HTTP Authentication without the application being able to verify or validate the authentication, an app can be vulnerable to replay and spoofing attacks.

The solution Scott came up with is a common one, and as the potential security implications are non-obvious (that is, until they are, of course :) ), they often go unnoticed.

OK, now for some explanation. These are the things that occurred to me while thinking about Scott’s situation:

  1. If Apache is not looking at LDAP, or there are subdirectories (or siblings) that are not also set up with all the necessary bits to have Apache look at LDAP, then you could be vulnerable. However, if you are doing all that extra work, you’ll be fine.

    There is nothing in the HTTP protocol that can be used to revoke HTTP Authentication once access is granted, but, this makes sense given the way that the HTTP protocol itself works. The only way to clear the authentication is to close the browser. Depending on which browser(s) visitors are using, they may have to close just the tab or window in question, or they may have to close out all instances of the program (though this is much more rare today than it used to be).

    Because of this, control over continuing validity of access is now in the hands of the user, not the system. This alone is one of those general great-big-no-no items in security. The user should be able to decide, “I’m done, log me out,” but the system should also be able to say, “Thank you, come again!” In addition, this situation can lead to all sorts of weird and unexpected problems in your application(s). Belive me, it sucks. I know because I’ve dealt with some of them before.

    At this point, one might start to think, “OK. So I can’t revoke access using HTTP. Why not set a flag in the DB when I authenticate and remove that when a user clicks on the ‘logout’ button?” First problem, there is no DB as far as Apache is concerned. Remember, it’s using LDAP, and the mod_authz_ldap module can only do the LDAP authentication. One could start creating a web of code here to compensate, but I think there are much easier ways. Second, what happens if the user doesn’t click “logout”? There’s a really good reason right there to build the authentication into the application rather than use HTTP Authentication.

  2. There are two kinds of attacks this architecture could leave an application vulnerable to. However, if the webserver is successfully protecting every single subdirectory involved (i.e. issue 1 isn’t an issue), then these attacks should be quite a bit more difficult to mount:
    1. Replay attack: A replay attack is when one simply records the packets going by and then “replays” them back to the server, changing the source IP address (and probably the port, too). The attacker doesn’t have to know the magic incantation (password, etc.), they just get in.

      In the context that I’m talking about in this post, it might be possible to replay the HTTP headers that followed successful authentication, or the headers from the authentication step itself.

    2. Spoofing attack: A spoof is when one constructs packets that pretend to be what an application expects. In the case of web based applications, it is very common to see developers use the “Referrer” security model (which isn’t secure in the least). That’s where their pages assume, “you must have authenticated successfully, since you were referred here by the login page.”

      In this case, the entire authentication step could possibly be bypassed. This will depend on some other factors and even if it can’t be bypassed directly, then someone could use a replay attack or simply reuse someone else’s session by snarfing a browser that had a window (or tab) open to the app. Since the app can not verify that authentication actually took place (since it can’t get involved with LDAP or other verification), it can only assume that it must have been successful if you are getting “here” from “there” because it sees the browser presenting information that it should only have if it is coming from “there”. The problem is, that information is unreliable and easy to forge.

Here are some other ideas to help deal with it.

When it comes to web applications and the need for authenticated access, the only way to make sure that authentication is enforced is to wrap every protected page generation operation within a “blanket” of verifying the authentication. Here is a simple pseudo-code example:

if (logging_in) // In other words, we're processing the login page.
{
   result = login_function ();
   if (result)
   {
      already_logged_in = TRUE;
   }
   else
   {
      Redirect back to the login page, perhaps showing an error.
   }
}

if (already_logged_in)
{
   if (verify_authentication ())
   {
      Deal with generating/providing the requested page.
   }
   else
   {
      Go to the login page.
   }
}

As you can see from this sample, the same authentication system can re-verify that the user is still authenticated and that the connection is valid for each and every page generation. There is no other pathway to the meat. This kind of architecture is necessary with a stateless protocol like HTTP. Anything less and there will be other ways in.

I see six possible solutions for Scott’s specific problem of Django not supporting LDAP:

  1. Wait for Django to get LDAP support
  2. Write your own, separate authentication into your application (using the DB)
  3. Use a Python LDAP “library” and hook your authentication into your app
  4. Write the LDAP support for Django
  5. Write PAM support for Django (or just your app)
  6. Run

Number 6 means to abandon Django and use a framework which has already taken security seriously, or build one yourself.

I don’t know much about Django. Perhaps it’s just too new and is still missing a lot of key pieces. Perhaps the developers don’t think LDAP is a good way to work with authentication (they would be completely wrong). Whichever it is, it sounds to me like Django isn’t quite ready for prime time. Personally, I am very uncomfortable with it from both a security standpoint and as a framework, since it seems incomplete. I just know that if I were going to write a web app in Python (which I don’t), I would be looking elsewhere at this point. Who knows how many other problems you will run into with something like this.

However, if I were a big Python guy (again, I’m not) and I had some time I could dedicate to helping a project like Django out, I would look a little deeper to see if I thought this thing had real promise for the future. If so, then I would go with option 4 and contribute that back to the community.

Scott, whichever way you decide to take this response, good luck with your application and thanks for sharing your situation with us. For everyone else, I hope these rambling thoughts help.


Actions

Informations

2 responses to “Response: Django with HTTP Authentication”

5 07 2006
Hawley Smoot (14:02:59) :
6 07 2006
Peregrine (15:23:20) :

The support is brand new. Scott Paul Robertson discovered and pointed it out to me just a couple of days ago.

Leave a comment

You can use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>