2010-11-04 107 views
15

django_sessionsession_data被存儲,它首先使用python的pickle模塊進行pickle,然後使用python的base64模塊在base64中進行編碼。如何從django_session表中的session_data中查找用戶標識?

我得到了解碼的pickle session_data。從django_session中表

session_data是:

gAJ9cQEoVQ9fc2Vzc2lvbl9leHBpcnlxAksAVRJfYXV0aF91c2VyX2JhY2tlbmRxA1UpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmRxBFUNX2F1dGhfdXNlcl9pZHEFigECdS5iZmUwOWExOWI0YTZkN2M0NDc2MWVjZjQ5ZDU0YjNhZA== 

通過base64.decode解碼之後(session_data是):

\x80\x02}q\x01(U\x0f_session_expiryq\x02K\x00U\x12_auth_user_backendq\x03U)django.contrib.auth.backends.ModelBackendq\x04U\r_auth_user_idq\x05\x8a\x01\x02u.bfe09a19b4a6d7c44761ecf49d54b3ad 

我想從auth_user_idq\x05\x8a\x01\x02u 找出auth_user_id。請幫助我這樣做。

回答

25

我有麻煩與保羅的方法(見我對他的回答評論),所以我結束了使用這種方法從scottbarnham.com blog post

from django.contrib.sessions.models import Session 
from django.contrib.auth.models import User 

session_key = '8cae76c505f15432b48c8292a7dd0e54' 

session = Session.objects.get(session_key=session_key) 
uid = session.get_decoded().get('_auth_user_id') 
user = User.objects.get(pk=uid) 

print user.username, user.get_full_name(), user.email 
10

注:由於原來的答案格式改變,1.4及以上見下文

更新
import pickle 

data = pickle.loads(base64.decode(session_data)) 

>>> print data 
{'_auth_user_id': 2L, '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend', 
'_session_expiry': 0} 

[更新]

My base64.decode requires filename arguments, so then I tried base64.b64decode, but this returned "IndexError: list assignment index out of range".

我真的不知道爲什麼我用的base64模塊,我猜是因爲這個問題。

您可以只使用str.decode方法:從用戶來源

>>> pickle.loads(session_data.decode('base64')) 
{'_auth_user_id': 2L, '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend', 
'_session_expiry': 0} 

I found a work-around (see answer below), but I am curious why this doesn't work.

加載醃數據(餅乾)是一個安全隱患,所以session_data是格式被改變,因爲這個問題,得到的回答(我應該追蹤Django的bug跟蹤器中的特定問題並將其鏈接到此處,但我的番茄時間休息消失了)。

現在的格式(自Django 1.4開始)是「hash:json-object」,其中前40個字節的散列是加密簽名,其餘的是JSON有效載荷。現在,您可以忽略哈希(它允許檢查數據是否未被某些cookie黑客篡改)。

>>> json.loads(session_data.decode('base64')[41:]) 
{u'_auth_user_backend': u'django.contrib.auth.backends.ModelBackend', 
u'_auth_user_id': 1} 
+0

這對我來說不適用於使用Python 2.7和Django 1.4。我的'base64.decode'需要文件名參數,所以我嘗試'base64.b64decode',但是這返回「IndexError:列表分配索引超出範圍」。我發現了一個解決方法(見下面的答案),但我很好奇爲什麼這不起作用。 – 2012-08-21 13:47:05

+1

@dolan:看到更新後的答案,由於安全考慮,session_data格式發生了變化。 – 2013-10-15 22:11:40

2
from django.conf import settings 
from django.contrib.auth.models import User 
from django.utils.importlib import import_module   

def get_user_from_sid(session_key): 
    django_session_engine = import_module(settings.SESSION_ENGINE) 
    session = django_session_engine.SessionStore(session_key) 
    uid = session.get('_auth_user_id') 
    return User.objects.get(id=uid) 
1

如果您想了解更多關於它並知道如何編碼或解碼工作,有一些相關的代碼。 順便說一下,我使用的Django版本是1.9.4。

Django的/的contrib /會話/後端/ base.py

class SessionBase(object): 
    def _hash(self, value): 
     key_salt = "django.contrib.sessions" + self.__class__.__name__ 
     return salted_hmac(key_salt, value).hexdigest() 
    def encode(self, session_dict): 
     "Returns the given session dictionary serialized and encoded as a string." 
     serialized = self.serializer().dumps(session_dict) 
     hash = self._hash(serialized) 
     return base64.b64encode(hash.encode() + b":" + serialized).decode('ascii') 
    def decode(self, session_data): 
     encoded_data = base64.b64decode(force_bytes(session_data)) 
     try: 
      # could produce ValueError if there is no ':' 
      hash, serialized = encoded_data.split(b':', 1) 
      expected_hash = self._hash(serialized) 
      if not constant_time_compare(hash.decode(), expected_hash): 
       raise SuspiciousSession("Session data corrupted") 
      else: 
       return self.serializer().loads(serialized) 
     except Exception as e: 
      # ValueError, SuspiciousOperation, unpickling exceptions. If any of 
      # these happen, just return an empty dictionary (an empty session). 
      if isinstance(e, SuspiciousOperation): 
       logger = logging.getLogger('django.security.%s' % 
         e.__class__.__name__) 
       logger.warning(force_text(e)) 
      return {} 

Django的/的contrib /會話/ serializer.py

class JSONSerializer(object): 
    """ 
    Simple wrapper around json to be used in signing.dumps and 
    signing.loads. 
    """ 
    def dumps(self, obj): 
     return json.dumps(obj, separators=(',', ':')).encode('latin-1') 
    def loads(self, data): 
     return json.loads(data.decode('latin-1')) 

讓我們專注於SessionBase的編碼功能。

  1. 序列化會話字典的JSON
  2. 創建哈希鹽
  3. 鹽添加到系列化會議,Base64編碼的串聯

因此,解碼是逆。 我們可以在下面的代碼中簡化解碼功能。

import json 
import base64 
session_data = 'YTUyYzY1MjUxNzE4MzMxZjNjODFiNjZmZmZmMzhhNmM2NWQzMTllMTp7ImNvdW50Ijo0fQ==' 
encoded_data = base64.b64decode(session_data) 
hash, serialized = encoded_data.split(b':', 1) 
json.loads(serialized.decode('latin-1')) 

而session.get_decoded()做了什麼。

相關問題