【问题标题】:Django sessions: changing session key when modifiedDjango会话:修改时更改会话密钥
【发布时间】:2012-06-26 22:03:38
【问题描述】:

我正在设置支付网关并使用会话跨页面请求存储数据。下面的类用于组织和存储会话信息。

class Gateway:
  def __init__(self, session_key=None, session_name="FOO"):
    # Store session ID and name
    self.session_key    = session_key
    self.session_name   = session_name

    # Get the session
    session = SessionStore(session_key=self.session_key)

    try :
      data = session[self.session_name]
    except :
      data  = {user_id:None, checked_in:False }

    self.__dict__.update(data)

  def save(self) :
    session = SessionStore(session_key=self.session_key)
    session[self.session_name] = deepcopy(self.__dict__)
      try :
        del session['session_key']
        del session['session_name']
      except :
        pass
    session.save()

此视图检查用户是否已登录。如果他/她已登录,则他/她将被重定向。如果没有,他/她会被要求以访客身份登录或登记。

def check_in(request):
  gateway = Gateway(session_key=request.session.session_key)

  if request.user.is_authenticated():
    gateway.user_id = request.user.id
    gateway.checked_in = True
    gateway.save()

    return redirect('next_step')
  else:
    login_form = FormLogin()
    if request.POST:
      data = request.POST.copy()
      if 'login' in data:
        login_form = FormLogin(data)
        if login_form.is_valid():
          user = login(request, login_form)
            if user:
              gateway.user_id = user.id
              gateway.checked_in = True
              gateway.save()
              return redirect('next_step')
        elif 'guest' in data:
          gateway.checked_in = True
          gateway.save()
          return redirect('next_step')
    return render(
      request,
      'shop/login.html',
      {
        'login_form':login_form,
      }
    )

下一个视图检查“checked_in”变量。这是为了确保用户不会跳过登录/签入过程。 (作为旁注,函数“login(request,login_form)”是一个在其他上下文中完美运行的函数,如果成功则返回用户,否则返回 None)

def next_step(request):
  gateway = Gateway(session_key=request.session.session_key)

  if not gateway.checked_in:#edited 
    messages.info(request, _(u'You must specify login first.'))
    return redirect('check_in')
  else:
    #do the next step

现在解决问题:

即使用户通过身份验证,“checked_in”变量仍然为假,并导致视图循环。每次我设置变量并保存时,都会创建一个具有新会话 ID 的新会话。 django 文档对会话的修改有一些解释,但我无法理解为什么要创建新会话或会话密钥发生变化的原因。

编辑: 我正在使用数据库后端。

【问题讨论】:

  • 我不确定网关类的意义。除了充当会话中某些数据的持有者之外,它似乎没有做任何事情,您可以更轻松地通过会话本身直接访问这些数据。
  • 我还没有写完整的课。一旦我可以正确保存会话,它将更加有用。
  • del session['session_key'] 看起来应该是del session[self.session_name]['session_key'],类似于下面的行。不要认为这与您的问题有任何关系。
  • 你在使用数据库会话后端吗?
  • 是的,我正在使用数据库后端。我会在上面指定。

标签: python django session cookies session-cookies


【解决方案1】:

我已经复制了这个错误/问题:

网址规则

url(r'^test/', 'shop.views.catalog.test', name="test")

查看功能

def test(request) :
    key1 = request.session.session_key
    request.session['test'] = 'test'
    key2 = request.session.session_key

    raise Exception("%s : %s === %s" % (key1, key2, request.session['test']))
  1. 清除 127.0.0.1 的 cookie
  2. 转到 127.0.0.1:8000/test/
    • /test/ 处的异常 4793f2453758d7021a43a348a0f40a83 : 8568f729991e740395179c56cd37cf18 === 测试
  3. 刷新页面(不清除 cookie)
    • /test/ 处的异常 8568f729991e740395179c56cd37cf18 : 8568f729991e740395179c56cd37cf18 === 测试

所以在我的会话第一次被修改之前,我有一个不同的会话密钥......意外行为。我也很好奇为什么。

【讨论】:

    【解决方案2】:

    如果没有访问或修改数据库,Django 不会将会话持久化,所以我相信你用来初始化 SessionStore 的 session_key 实际上并没有数据库条目支持。

    如果是这种情况:当您保存 SessionStore 时,它​​将自动分配一个新的 session_key [1](因为数据库中不存在现有密钥,我们希望避免会话固定 [2])并保存到数据库,但客户端不会被分配这个新的 session_key,因为您的 SessionStore 独立于 request.session (保持未修改)。

    [1]https://github.com/django/django/blob/master/django/contrib/sessions/backends/db.py#L22

    [2]https://groups.google.com/forum/?fromgroups#!topic/django-users/8b_6oTaXv7Q

    测试这个假设的简单解决方法是在初始化网关类之前设置 request.session['kate'] = 'bob',因为这会强制 request.session 被持久化。您可能希望重构 Gateway 类,以便需要访问会话的方法将 request.session 作为参数。

    【讨论】:

    • 我正在使用 check_in 视图之前的视图中的会话,因此会话已被修改并存储在数据库中。在实例化网关之前,我仍然添加了 request.session['test'] = 'test',但发生了同样的问题。
    • 感谢您的解释。我没有经验,甚至不知道会话固定攻击。谢谢!
    • 对不起,没有想法(除非 request.session 在请求结束时被保存,从而覆盖您的数据,但这并不能解释新的会话密钥)。也许大量的日志记录会指向罪魁祸首。
    • 将 request.session 传递给需要它的方法将保存几个数据库请求,并且如果您(或同事)也开始修改 request.session,可能会避免丢失更新就像使用你的网关类一样。
    【解决方案3】:

    检查您的SESSION_COOKIE_SECURE 值并确保您在True..时使用HTTPS

    https://github.com/lepture/flask-wtf/issues/76

    【讨论】:

    • 问题是针对 Django 的。这个答案链接到 Flask ......这些不是同一个框架。
    猜你喜欢
    • 2012-12-08
    • 1970-01-01
    • 2011-01-11
    • 2021-09-02
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    相关资源
    最近更新 更多