2010-11-04 15 views
15

W django_session przechowywana jest tabela session_data, która jest najpierw kiszona przy użyciu modułu pikle Pythona, a następnie kodowana w base64 za pomocą modułu base64 z Pythona.jak znaleźć identyfikator użytkownika z session_data z tabeli django_session?

Mam dekodowane pikowane session_data.

session_data z tabeli django_session:

gAJ9cQEoVQ9fc2Vzc2lvbl9leHBpcnlxAksAVRJfYXV0aF91c2VyX2JhY2tlbmRxA1UpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5kcy5Nb2RlbEJhY2tlbmRxBFUNX2F1dGhfdXNlcl9pZHEFigECdS5iZmUwOWExOWI0YTZkN2M0NDc2MWVjZjQ5ZDU0YjNhZA== 

po zdekodowaniu go 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 

Chcę dowiedzieć się auth_user_id z auth_user_idq\x05\x8a\x01\x02u . Proszę, pomóż mi to zrobić.

Odpowiedz

25

miałem problemy z metodą Paulo (patrz mój komentarz na jego odpowiedź), więc skończyło się przy użyciu tej metody z 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

UWAGA: Format zmieniło od oryginalnej odpowiedzi na 1,4 i powyżej patrz aktualizacja poniżej

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} 

[aktualizacja]

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

ja naprawdę nie wiem, dlaczego użyłem modułu base64, Chyba dlatego, że zawierało to pytanie.

można po prostu użyć metody 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.

wczytywanie marynowane danych ze źródeł użytkowników (cookies) to zagrożenie dla bezpieczeństwa, więc session_data Format został zmieniony, ponieważ kwestia ta została wysłuchana (powinienem idź po konkretnym problemie w narzędziu do śledzenia błędów Django i połącz go tutaj, ale moja przerwa pomodoro zniknęła).

Format teraz (od Django 1.4) to "hash: json-object", gdzie pierwszy 40-bajtowy hash to krypto-podpis, a reszta to ładunek JSON. Na razie możesz zignorować hash (pozwala to sprawdzić, czy dane nie zostały zmienione przez jakiegoś hackera ciasteczek).

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

To nie będzie działało dla mnie przy użyciu Pythona 2.7 i Django 1.4. Mój 'base64.decode' wymaga argumentów nazw plików, więc wypróbowałem' base64.b64decode', ale ten zwrócił indeks IndexError: index przypisania poza zasięgiem. Znalazłem obejście (zobacz odpowiedź poniżej), ale jestem ciekawy, dlaczego to nie działa. –

+1

@dolan: zobacz zaktualizowaną odpowiedź, format session_data został zmieniony ze względu na obawy dotyczące bezpieczeństwa. –

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

Jeśli chcesz dowiedzieć się więcej o to i wiem jak działa kodowanie lub dekodowanie, jest jakiś odpowiedni kod. Nawiasem mówiąc, wersja Django, której używam, to 1.9.4.

django/contrib/sesje/backendy/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/sesje/serializer.py ostrości

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')) 

Miejmy na funkcję kodowania SessionBase użytkownika.

  1. Serializować słownika sesji do json
  2. utworzyć sól hash
  3. dodać sól do serializowane sesji base64 konkatenację

Więc dekodowania jest odwrotna. Możemy uprościć funkcję dekodowania w następującym kodzie.

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')) 

I to, co zrobił session.get_decoded().