如何从django_session表中查找session_data中的用户ID?

Ket*_*ale 21 python django pickle pinax

django_sessionsession_data中存储,首先使用python的pickle模块进行pickle,然后使用python的base64模块在base64中进行编码.

我得到了解码的pickle session_data.

来自django_session表的session_data:

gAJ9cQEoVQ9fc2Vzc2lvbl9leHBpcnlxAksAVRJfYXV0aF91c2VyX2JhY2tlbmRxA1UpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmRxBFUNX2F1dGhfdXNlcl9pZHEFigECdS5iZmUwOWExOWI0YTZkN2M0NDc2MWVjZjQ5ZDU0YjNhZA==
Run Code Online (Sandbox Code Playgroud)

在通过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
Run Code Online (Sandbox Code Playgroud)

我想找出auth_user_idfrom 的价值auth_user_idq\x05\x8a\x01\x02u .请帮我这样做.

Dol*_*cci 33

我在使用Paulo的方法时遇到了麻烦(请参阅我对他的回答的评论),所以我最终在scottbarnham.com博客文章中使用了这个方法:

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
Run Code Online (Sandbox Code Playgroud)


Pau*_*ine 12

注意:自原始答案后格式已更改,对于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}
Run Code Online (Sandbox Code Playgroud)

[更新]

我的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}
Run Code Online (Sandbox Code Playgroud)

我找到了解决办法(见下面的答案),但我很好奇为什么这不起作用.

从用户来源(cookies)加载腌制数据存在安全风险,因此自从回答了这个问题后,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}
Run Code Online (Sandbox Code Playgroud)


小智 5

如果您想了解更多信息并了解编码或解码的工作原理,请参阅一些相关代码。顺便说一下,我使用的 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 {}
Run Code Online (Sandbox Code Playgroud)

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'))
Run Code Online (Sandbox Code Playgroud)

让我们专注于 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'))
Run Code Online (Sandbox Code Playgroud)

这就是 session.get_decoded() 所做的。