"In order to login, a user will be presented with a
standard html form on a page that may or may not be
encrypted, at this point SSL is not relevant."
SSL is -quite- relevant at this point. You are specifically addressing MITM situations, and an MITM can, if you do not use SSL to send the log in form, send a modified login form which either posts to a different attacker-controlled server or simply attempts to post to your server in the clear, allowing the attacker to capture the users credentials in cleartext.Also, it seems that after you use the SSL session to get the AES-encrypted cookies to the user, the user still has to have an AES key stored on their system (and the AES key is what allows the user to continue making requests by proving the user's knowledge thereof by encrypting randomly generated "hashes" and getting new AES keys). What would prevent an MITM attacker, once you are no longer using SSL, from sending down a modified page to the user with malicious javascript that sends the user's current AES key to the attacker, thereby allowing the attacker to hijack the user's session?
While this scheme -should- prevent offline/passive replay attacks, it does not seem to mitigate an active Man-In-The-Middle attack.
ADD: What I would suggest if you could not afford to run your site in full-SSL, is that you require SSL for any operation that is not a READ or is a read of sensitive account info. Don't allow a user to post messages, delete records, etc. over regular HTTP. If some MITM steals your users cookies, then they will at best be able to, say, read a bit more of your user's mail than they would have been able to had they just sniffed the portion that your user actually requested. (Not that I would ever recommend not using full-SSL for email. Remember "Forgot your password?") Also, do not give a "Remember this computer forever" option when not using full-SSL (or at least make the "forever" cookie a secure cookie and still expire the non-secure session cookie) and ALWAYS expire cookies on the server side.
Since I wrote the article I have made some small adjustments to the AES key dialogue, they key is generated at the login form using javascript then sent as an ssl cookie to the authentication form and also stored into a local persistent storage, which is not accessible (barring an exploit.) Once the auth page is reached the aes and guid cookies are cleared. I suppose that a script could be crafted to cause the user to reveal the key and guid stored in persistent storage, this is something I am still working on securing against.
I will consider your suggestions carefully and attempt to integrate them as I work to code this out.
I have posted this discussion into the comments in the article and will be updating it tonight to reflect this conversation. Thank You.
then how do you guarantee the form is going to submit to an SSL-protected resource? the form and all of your javascript has to be sent over SSL, otherwise any of it can be tampered with to simply bypass your logic and post the form contents to an unencrypted resource.
if you haven't already seen it, watch moxie's blackhat presentation about ssl:
https://www.blackhat.com/html/bh-dc-09/bh-dc-09-archives.htm...
More significantly, this doesn't actually prevent replay attacks either. There are essentially two "cookies" (I'm oversimplifying) - long term, and single session cookies. If you catch the single session cookie, you can use it until it expires, at least according to the writeup.
This recommended approach is not good security practice for password storage. If the database is compromised, your passwords are vulnerable to rainbow table attacks. See http://en.wikipedia.org/wiki/Rainbow_table