代码之家  ›  专栏  ›  技术社区  ›  Ketan Yekale

如何从django_会话表的会话数据中查找用户ID?

  •  20
  • Ketan Yekale  · 技术社区  · 14 年前

    django_session 桌子 session_data 首先使用python的pickle模块进行pickle存储,然后使用python的base64模块进行base64编码。

    我得到了解码后的腌制会话数据。

    Django_会话表中的会话数据:

    gAJ9cQEoVQ9fc2Vzc2lvbl9leHBpcnlxAksAVRJfYXV0aF91c2VyX2JhY2tlbmRxA1UpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmRxBFUNX2F1dGhfdXNlcl9pZHEFigECdS5iZmUwOWExOWI0YTZkN2M0NDc2MWVjZjQ5ZDU0YjNhZA==
    

    按base64解码后。解码(会话数据):

     \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_id auth_user_idq\x05\x8a\x01\x02u . 请帮我这么做。

    5 回复  |  直到 6 年前
        1
  •  30
  •   Dolan Antenucci    13 年前

    我对保罗的方法有困难(见我对他的回答的评论),所以我最终使用了一个 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
    
        2
  •  11
  •   RichVel    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}
    

    [更新]

    我的base64.decode需要文件名参数,所以我尝试了base64.b64decode,但返回了“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}
    

    我找到了一份工作(见下面的答案),但我很好奇为什么这不起作用。

    从用户源(cookie)加载pickled数据是一个安全风险,因此会话数据格式在回答此问题后发生了更改(我应该在Django的bug跟踪器中查找特定问题并将其链接到此处,但我的pomodoro中断已消失)。

    现在的格式(从Django1.4开始)是“hash:json对象”,其中前40字节的hash是加密签名,其余的是json负载。现在您可以忽略散列(它允许检查数据是否被某个cookie黑客篡改)。

    >>> json.loads(session_data.decode('base64')[41:])
    {u'_auth_user_backend': u'django.contrib.auth.backends.ModelBackend',
     u'_auth_user_id': 1}
    
        3
  •  3
  •   slav0nic    11 年前
    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)
    
        4
  •  3
  •   headmaster    9 年前

    如果您想了解更多关于它的信息,并且知道编码或解码是如何工作的,那么有一些相关的代码。 顺便说一下,我使用的django版本是1.9.4。

    django/contrib/sessions/backend/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/sessions/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. 将salt添加到序列化会话,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()所做的。

        5
  •  0
  •   drchuck    6 年前

    我想用纯Python和最新版本的django(2.05)来实现这一点。我就是这样做的:

    >>> import base64
    >>> x = base64.b64decode('OWNkOGQxYjg4NzlkN2ZhOTc2NmU1ODY0NWMzZmQ4YjdhMzM4OTJhNjp7Im51bV92aXNpdHMiOjJ9')
    >>> print(x)
    b'9cd8d1b8879d7fa9766e58645c3fd8b7a33892a6:{"num_visits":2}'
    >>> import json
    >>> data = json.loads(x[41:])
    >>> print(data)
    {'num_visits': 2}