【问题标题】:Pyramid.security: Is getting user info from a database with unauthenticated_userid(request) really secure?Pyramid.security:从具有 unauthenticated_userid(request) 的数据库中获取用户信息真的安全吗?
【发布时间】:2017-04-24 22:34:10
【问题描述】:

我正在尝试使用 Pyramid 文档的“Making A “User Object” Available as a Request Attribute”示例对用户数据进行可访问缓存。

他们正在使用此代码将用户对象返回给 set_request_property:

from pyramid.security import unauthenticated_userid

def get_user(request):
    # the below line is just an example, use your own method of
    # accessing a database connection here (this could even be another
    # request property such as request.db, implemented using this same
    # pattern).
    dbconn = request.registry.settings['dbconn']
    userid = unauthenticated_userid(request)
    if userid is not None:
        # this should return None if the user doesn't exist
        # in the database
        return dbconn['users'].query({'id':userid})

我不明白他们为什么要使用 unauthenticated_userid(request) 从数据库中查找用户信息……这不是不安全吗?这意味着该用户可能没有登录,那么您为什么要使用该 ID 从数据库中获取私人信息?

不应该

    userid = authenticated_userid(request)

用于确保用户已登录?使用 unauthenticated_userid(request) 有什么好处?请帮助我了解这里发生了什么。

【问题讨论】:

    标签: python authentication security pyramid


    【解决方案1】:

    unauthenticated_userid 通话更便宜;它会从请求中查找用户 ID,而无需经历整个身份验证过程再次。

    这里的关键概念是再次这个词。您应该只在已授权的视图中使用该方法。换句话说,当您到达使用 unauthenticated_userid 的代码时,您已经已经验证了用户,并且特别不想为这个特定的调用再次这样做。

    根据后端持久存储对用户进行身份验证可能会很昂贵,尤其是在此类存储不支持缓存的情况下。 unauthenticated_userid API 方法是一种优化,其中请求基本上是您的 userid 缓存。

    【讨论】:

    • 是否 authenticated_userid() 不做同样的事情(只返回一个 ID)?我在代码中没有看到 authenticated_userid 尝试重新验证或重新查询我的数据库的任何地方。我认为当我调用headers = remember(self.request, userID) 时,它只是将静态ID 安全地存储在cookie 中,并在我调用authenticated_userid() 时检索。它是否在我不知道的背景中做一些更昂贵的事情?
    • @yourfriendzak:default 实现不需要在后端数据库中查找任何用户。该 API 存在于 specialized 实现中。
    • @yourfriendzak:请注意,例如,CallbackAuthenticationPolicy.authenticated_userid 首先调用CallbackAuthenticationPolicyunauthenticated_userid,然后使用回调来验证该用户ID。回调可能代价高昂。
    • 当您说“CallbackAuthenticationPolicyunauthenticated_userid”时,您的意思是 AuthTktAuthenticationPolicy(secret='thesecret', callback=groupfinder)?
    • 那么在你的情况下不要使用unauthenticated_userid,只使用authenticated_userid。
    【解决方案2】:

    这是一个迟到的回复,但它被链接为 Pyramid 的一些用户的混淆来源。

    这里接受的答案并不是unauthenticated_userid 用于request.user 的实际原因。它与性能无关。

    它使用unauthenticated_userid 的原因是因为它可以更轻松地在应用程序之间重用身份验证策略,只需进行较小的修改。您的应用程序需要一个“事实来源”来确定是否允许将用户视为已通过身份验证,并且通常策略的内部逻辑不足以做出此决定。一个有效的 cookie 很好,但您通常希望在信任它之前与您的后端进行验证。太好了,那么我们把这个逻辑放在哪里呢? unauthenticated_userid 没有意义,因为它是策略的可重用部分,专门专注于解析请求标头。您可以将其放入authenticated_userid,但此方法不是您通常在应用程序中关心的方法。你通常在你的应用程序中使用request.user(你可能很少直接关心request.authenticated_userid),最后request.user是功能的超集——它提供了一个完整的用户对象,而不仅仅是一个id。在大多数情况下,在不验证整个对象的情况下验证 id 是很愚蠢的。我们只能有一个“真相来源”,因此配方声明它为request.user。 groupfinder(因此authenticated_userid)现在可以依赖request.user,并相信它从那里返回的内容已通过后端正确验证。此外,request.user 已经被具体化,因此自然会加快对request.authenticated_userid 的后续调用。

    【讨论】:

      【解决方案3】:

      看起来 Martijn Pieters 是对的。

      我的微基准测试(在我的项目中,我使用 Redis 作为用户和其他一切的数据库):

      print ('start test')
      t1 = time()
      authenticated_userid(self.request)
      print ('authenticated: ' + str(time()-t1))
      t1 = time()
      unauthenticated_userid(self.request)
      print ('unauthenticated: ' + str(time()-t1))
      print ('test_stop')
      

      结果:

      start test
      REDIS AUTH! # <-- actually this is query to groups finder in Redis
      authenticated: 0.00032901763916
      unauthenticated: 7.31945037842e-05
      test_stop
      

      它被测试了几次,结果是不变的 :) 你认为我应该在 Pyramid 文档中添加 Martijn 对那篇文章的回答以使事情更“清晰”吗? :)

      【讨论】:

      • 好的,那么 authenticated_userid(self.request) 到底是怎么做的呢?它调用了什么函数?
      • 在我的特殊情况下(只有一件事我可以肯定地说),它调用了我的 groupfinder 函数,它检查用户的组。所以我会说,也许 authenticated_userid 会检查用户会话,并且只有在它有效的情况下 - 返回用户名。
      猜你喜欢
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-19
      • 2012-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多