Take the 2-minute tour ×
Information Security Stack Exchange is a question and answer site for Information security professionals. It's 100% free, no registration required.

I'm writing a web service which stores data which will be shared between two separate systems.

/session/requestNewSession?args=<data> => returns session id

/session/requestArgs?session=<session id> => returns <data> stored with key <session id>

The code is implemented in python in the twisted matrix library, and I've written my own session id generator:

private_secret = os.urandom(64)
def generateRandomSessionKey():
 rawdata = private_secret + str(time.time()) + string.join(map(chr, [random.randint(0,255) for x in range(100)]),"")
 session_key = hashlib.sha256(rawdata).hexdigest()
 del(rawdata)
 return session_key

Is this a proper way of generating a secure session id (unguessable)? If not, any ideas on what I should do differently?

share|improve this question
add comment

1 Answer

up vote 4 down vote accepted

Answer. Yes. This is a fine way to generate a session ID.

Rationale. The private_secret will be unguessable and cryptographically strong (that is guaranteed by urandom()). So, all you need is that the combination of time.time() and your random.randint() numbers are unique: that combination should never repeat. That should be pretty much guaranteed. The Python random number generator shouldn't repeat for a long time, so you should be fine.

For more, see Is a rand from /dev/urandom secure for a login key? for a related question.

Caveat. The only risk factor I can see would be: if you run the server process in a VM, starting from the same checkpoint every time. (In other words, before deployment you boot up the guest OS in the VM once and checkpoint it at that point; then every time you start up your web service, you start it up from that checkpoint.) In that situation, os.urandom(), time.time(), and random.randint() could all repeat, causing you to allocate the same session ID to two different clients. But as long as you don't use a VM in that way, you should be fine.

An alternative. A simpler way and just-as-secure implementation would be to use the following:

def generateRandomSessionKey():
    return hexify(os.urandom(16))
share|improve this answer
    
+1 for the much shorter and more elegant solution. If you must implement your own sessions, then keep it simple. If you already use a good enough random source, adding time() won't help much but just makes things slower and more complicated (same goes to string joins, maps etc)... complicated == more chances of errors. –  Yoav Aner Apr 30 '12 at 10:24
    
cannot excessive use of os.urandom() block on some OS implementations? –  Dog eat cat world Apr 30 '12 at 11:00
    
@Dogeatcatworld, no: as far as I know os.urandom() will never block. At least, not on any OS platform I am familiar with. (On Unix, internally it uses /dev/urandom, not /dev/random. /dev/urandom doesn't block -- you may be thinking of /dev/random, which can block, but you should always use /dev/urandom not /dev/random. On Windows, it uses CryptGenRandom(), which should never block, either.) –  D.W. Apr 30 '12 at 22:21
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.