#!/usr/bin/env python
'''
Decode (and encode) Django session data.
'''
import base64
import hmac
import hashlib
import pickle
def session_utoken(msg, secret_key, class_name='SessionStore'):
'''
Get the unique session token.
@param msg The message string.
@param secret_key The SECRET_KEY from the Django settings.py file.
@param class_name The class name. This is emulates the SessionBase
_hash() function in Django.
@returns The unique session token.
'''
key_salt = "django.contrib.sessions" + class_name
sha1 = hashlib.sha1((key_salt + secret_key).encode('utf-8')).digest()
utoken = hmac.new(sha1, msg=msg, digestmod=hashlib.sha1).hexdigest()
return utoken
def encode(session_dict, secret_key, class_name='SessionStore'):
'''
Encode Django session data using the secret key from the settings.py file.
This code is completely independent of Django so it can be used by
third party tools.
@param session_dict The session data as a dictionary from Django.
@param secret_key The SECRET_KEY from the Django settings.py file.
@param class_name The class name. This is emulates the SessionBase
_hash() function in Django.
@returns the session data as a dictionary
'''
pickled = pickle.dumps(session_dict, pickle.HIGHEST_PROTOCOL)
utoken = session_utoken(pickled, secret_key, class_name)
cipher = base64.b64encode(utoken.encode() + b':' + pickled)
return cipher.decode()
def decode(session_data, secret_key, class_name='SessionStore'):
'''
Decode Django session data using the secret key from the
settings.py file and verifying it.
This code is completely independent of Django so it can be used by
third party tools.
@param session_data The session data from Django.
@param secret_key The SECRET_KEY from the Django settings.py file.
@param class_name The class name. This is emulates the SessionBase
_hash() function in Django.
@returns the session data as a dictionary
'''
encoded_data = base64.b64decode(session_data)
utoken, pickled = encoded_data.split(b':', 1)
expected_utoken = session_utoken(pickled, secret_key, class_name)
if utoken.decode() != expected_utoken:
raise BaseException('Session data corrupted "%s" != "%s"',
utoken.decode(),
expected_utoken)
return pickle.loads(pickled)
def _test():
'''
Internal test of the encode/decode functions.
'''
# Some sample data.
SECRET_KEY = r'spdB<HnIQxod4/2pRkjo_<buak@^DVykOf8~bI]@N.cF\~b)'
sdx = ['NWQ0NGFmNTRjZmNhYWI4ZDIwZmE2ODk4MmVlNjI4NWM1M2IyODQ1NzqAAn1xAChVBHRoaXNxAVUEdGhhdHECVQZzZWNyZXRxA1UEaHVzaHEEdS4=',
'YzZkZmM0N2JkZjIwZjA3ZjUyODZiNDMzOTQwYTZmZTA3Y2RjYzhmMzqAAn1xAC4=',
]
passed = 0
failed = 0
total = 0
for data in sdx:
print
print 'TEST'
print ' data = %d %s' % (len(data), data)
dec = decode(data, SECRET_KEY)
print ' decode = %r' % (repr(dec))
enc = encode(dec, SECRET_KEY)
print ' encode = %r' % (repr(enc))
decx = decode(enc, SECRET_KEY)
print ' decode1 = %r' % (repr(decx))
total += 1
if dec == decx:
passed += 1
print ' status = PASSED'
else:
failed += 1
print ' status = FAILED'
print
print 'SUMMARY total=%d, passed=%d, failed=%d' % (total, passed, failed)
if failed:
print 'RESULT: FAILED'
else:
print 'RESULT: PASSED'
print
if __name__ == '__main__':
_test()
Decode Django session data without the infrastructure
I recently had to access Django session data from a cookie in a third party application (based on Tomcat) with no access to the Django infrastructure. This example shows how I did it.
The key is understanding that the session data is composed of two components: a unique token and the data separated by a colon (:).
The unique token is composed of various parts including the SECRET_KEY from settings.py. It is built using the data and the SHA1 hash algorithm. The token can be used to guarantee that the data is associated with the correct Django session.
The data is simply a pickled dictionary of plaintext data so it can be decoded without regard to the token and, by implication, the SECRET_KEY.
With this in mind, it is easy to see that the session data can be decoded by a third party application by simply unpickling it.
The data is secure because it is not available in the session cookie. The session cookie only contains the encrypted session key which references the session data in the context of the Django application. To access the data the 3rd party must have access to that context. In my case it would be done through the database.
Thank you! This was really useful