
Harald Meland writes:
As the extra complexity added by having to save session state on the server side (i.e. have Mailman keep track of session IDs) is rather large, and as Mailman isn't safe from package sniffing anyway (unless you're running things on a SSL server, in which case cookie sniffing shouldn't be of any trouble anyway), I settled for slightly less.
True. Though stealing a cookie via packet sniffing will still require the thief to be on the same IP as the original cookie owner, or it will require them to fake their IP as well. This definitely makes the list vulnerable to only an extremely determined attacker.
[Note, I'm not a python hacker, so bear with me :-) ]
Do add the domain that this mailman for this list is supposed to be under (or the browser will send this cookie to every site you connect to!) and restrict the scripts that it is sent to to /mailman/ at worst, /mailman/admin and /mailman/admindb separately at best (allowing separate passwords for those two scripts is a needed feature for a proper distinction between list admins and moderators, anyway).
Of course, you could already be doing this and I just missed it :-)
I have just commited a fix to CVS, based on these two new SecurityManager functions:
def MakeCookie(self): client_ip = os.environ.get('REMOTE_ADDR') or '0.0.0.0' issued = int(time.time()) expires = issued + mm_cfg.ADMIN_COOKIE_LIFE secret = self.password
I'd prefer to grab the secret from a file that's refreshed via a cronjob every 24hrs or so. Generate it from something like a CRC32 of some /dev/urandom output (on a linux box, anyway) would do the trick.
mac = hash(secret + client_ip + `issued` + `expires`)
Is the hash() function one way? How about:
import md5 import base64
mac = base64.encodestring(md5.new(secret + client_ip + issued
+ expires
).digest())
The FAQ talks about doing a second round of MD5 hashing to '...avoid an attack in which additional data is appended to the end of the cookie and a new hash recalculated by the attacker.', but I don't really understand why that's necessary.
With any luck, someone will have implemented an HMAC (see RFC 2104, http://www.it.kth.se/docs/rfc/rfcs/rfc2104.txt) module for python that we could use.
return [client_ip, issued, expires, mac] def CheckCookie(self, cookie): if type(cookie) <> type([]): return 0 if len(cookie) <> 4: return 0 client_ip = os.environ.get('REMOTE_ADDR') or '0.0.0.0' [for_ip, issued, expires, received_mac] = cookie if for_ip <> client_ip: return 0 now = time.time() if not issued < now < expires: return 0
Should we check that expires - issued = mm_cfg.ADMIN_COOKIE_LIFE ?
secret = self.password mac = hash(secret + client_ip + `issued` + `expires`)
See above.
if mac <> received_mac: return 0 return 1
Hopefully, this new cookie scheme will suffice -- if anyone do see flaws in it, don't hesitate to get in touch.
The combination of a cryptographic hashing function and a secret key that's regenerated on a 24hour cycle makes an attack by constructing a cookie infeasible (at least, within the useful lifetime of whatever hashing function we're using).
Remaining sources of attacks are:
Packet sniffing: They could steal the cookie this way. But they'd just steal the password, anyway, so it's a moot point. Use SSL if you're that paranoid.
Stealing the cookie: Presumably by some method other than packet sniffing or direct access to your terminal; maybe a broken browser could be distributing the cookie to every site it meets. The attacker will need to fake your IP to the web server _and_ get the response back, which is rather hard.
Getting access to your terminal: The short expiry time is supposed to help defeat this problem. The price to pay for the convenience of not having to type the password in every time.
Perhaps having an option to turn off the use of cookies will keep the paranoid happy and allow admins to use their servers native authentication methods. Perhaps modules to interface between mailman and the various different web servers is a direction someone would like to go in?
John.