4

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?

Savara
  • 490
  • 4
  • 15
Dog eat cat world
  • 5,769
  • 1
  • 27
  • 46

1 Answers1

5

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))
D.W.
  • 98,860
  • 33
  • 271
  • 588
  • +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
  • 1
    @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