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

Python 如何从django_会话表的会话_数据中查找用户id?,python,django,pickle,pinax,Python,Django,Pickle,Pinax,在django_session表session_中存储数据,数据首先使用python的pickle模块进行pickle,然后使用python的base64模块进行base64编码 我得到了已解码的pickle session_数据 django_会话表中的会话_数据: gAJ9cQEoVQ9fc2Vzc2lvbl9leHBpcnlxAksAVRJfYXV0aF91c2VyX2JhY2tlbmRxA1UpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJ

django_session
session_中存储数据
,数据首先使用python的pickle模块进行pickle,然后使用python的base64模块进行base64编码

我得到了已解码的pickle session_数据

django_会话表中的会话_数据:

gAJ9cQEoVQ9fc2Vzc2lvbl9leHBpcnlxAksAVRJfYXV0aF91c2VyX2JhY2tlbmRxA1UpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmRxBFUNX2F1dGhfdXNlcl9pZHEFigECdS5iZmUwOWExOWI0YTZkN2M0NDc2MWVjZjQ5ZDU0YjNhZA==
通过base64进行解码后。解码(会话_数据):

我想从
auth\u user\u idq\x05\x8a\x01\x02u

. 请帮助我这样做。

注意:自原始答案以来格式已更改,对于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:列表分配索引超出范围”

我真的不知道为什么我要使用base64模块,我想是因为这个问题突出了它

您可以使用
str.decode
方法:

>>> pickle.loads(session_data.decode('base64'))
{'_auth_user_id': 2L, '_auth_user_backend': 'django.contrib.auth.backends.ModelBackend',
 '_session_expiry': 0}
我找到了一个解决办法(见下面的答案),但我很好奇为什么这不起作用

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

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


我在保罗的方法上遇到了麻烦(见我对他的回答的评论),所以我最终使用了以下方法:


如果您想了解更多信息,了解编码或解码是如何工作的,这里有一些相关的代码。 顺便说一下,我使用的Django版本是1.9.4

django/contrib/sessions/backends/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的编码函数

  • 将会话字典序列化为json
  • 创建一个散列盐
  • 将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()就是这么做的。

    我想用最新版本的DJango(2.05)在纯Python中实现这一点。这就是我所做的:

    >>> 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}
    

    我只是需要在Django安装中解决类似的问题。我知道该用户的ID(36),并希望删除该特定用户的会话数据。我想把这段代码作为一个原型,用于在会话数据中查找用户:

    from django.contrib.sessions.models import Session
    
    TARGET_USER = 36  # edit this to match  target user.
    
    TARGET_USER = str(TARGET_USER)  # type found to be a string
    
    for session in Session.objects.all():
        raw_session= session.get_decoded()
        uid = session.get_decoded().get('_auth_user_id')
        if uid == TARGET_USER:  # this could be a list also if multiple users
            print(session)
            # session.delete()  # uncomment to delete session data associated with the user
    
    

    希望这对其他人有所帮助。

    这对我使用Python 2.7和Django 1.4是行不通的。我的
    base64.decode
    需要文件名参数,因此我尝试了
    base64.b64decode
    ,但这返回了“indexer:列表分配索引超出范围”。我找到了一个解决方法(请参见下面的答案),但我很好奇为什么这不起作用。@dolan:请参见更新的答案,由于安全问题,会话_数据格式已更改。
    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'))
    
    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'))
    
    >>> 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}
    
    from django.contrib.sessions.models import Session
    
    TARGET_USER = 36  # edit this to match  target user.
    
    TARGET_USER = str(TARGET_USER)  # type found to be a string
    
    for session in Session.objects.all():
        raw_session= session.get_decoded()
        uid = session.get_decoded().get('_auth_user_id')
        if uid == TARGET_USER:  # this could be a list also if multiple users
            print(session)
            # session.delete()  # uncomment to delete session data associated with the user