summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorPaul McMillan <Paul@McMillan.ws>2012-02-23 22:51:14 +0000
committerPaul McMillan <Paul@McMillan.ws>2012-02-23 22:51:14 +0000
commit1525874238fd705ec17a066291935a9316bd3044 (patch)
tree9ec5c31693492981606a0699c2c987e16c8b50e9 /django
parent239e41f7c551308cea64561eed43ef2e81b60370 (diff)
Improved get_random_string().
Improved the behavior of get_random_string to re-seed itself each time it is called if the system does not have a secure random number generator. This will change the properties of the random string produced, but will be unpredictable to an attacker. git-svn-id: http://code.djangoproject.com/svn/django/trunk@17581 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
-rw-r--r--django/utils/crypto.py24
1 files changed, 22 insertions, 2 deletions
diff --git a/django/utils/crypto.py b/django/utils/crypto.py
index a54c455e1b..44b7faf492 100644
--- a/django/utils/crypto.py
+++ b/django/utils/crypto.py
@@ -7,12 +7,18 @@ import struct
import hashlib
import binascii
import operator
+import time
+# Use the system PRNG if possible
import random
try:
random = random.SystemRandom()
+ using_sysrandom = True
except NotImplementedError:
- pass
+ import warnings
+ warnings.warn('A secure pseudo-random number generator is not available '
+ 'on your system. Falling back to Mersenne Twister.')
+ using_sysrandom = False
from django.conf import settings
@@ -47,11 +53,25 @@ def get_random_string(length=12,
allowed_chars='abcdefghijklmnopqrstuvwxyz'
'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'):
"""
- Returns a random string of length characters from the set of a-z, A-Z, 0-9.
+ Returns a securely generated random string.
The default length of 12 with the a-z, A-Z, 0-9 character set returns
a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
"""
+ if not using_sysrandom:
+ # This is ugly, and a hack, but it makes things better than
+ # the alternative of predictability. This re-seeds the PRNG
+ # using a value that is hard for an attacker to predict, every
+ # time a random string is required. This may change the
+ # properties of the chosen random sequence slightly, but this
+ # is better than absolute predictability.
+ random.seed(
+ hashlib.sha256(
+ "%s%s%s" % (
+ random.getstate(),
+ time.time(),
+ settings.SECRET_KEY)
+ ).digest())
return ''.join([random.choice(allowed_chars) for i in range(length)])