【问题标题】:Django user impersonation by admin管理员模拟 Django 用户
【发布时间】:2011-01-15 14:54:04
【问题描述】:

我有一个 Django 应用程序。当以管理员用户身份登录时,我希望能够在 URL 中传递一个秘密参数,并让整个网站的行为就像我是另一个用户一样。

假设我有一个 URL /my-profile/,它显示了当前登录的用户的个人资料。我希望能够执行/my-profile/?__user_id=123 之类的操作,并让底层视图相信我实际上是 ID 为 123 的用户(因此呈现 该用户的个人资料)。

我为什么要那个?

仅仅是因为重现某些只出现在单个用户帐户中的错误要容易得多。

我的问题:

  1. 实现这样的事情最简单的方法是什么?

  2. 在执行此操作时,我是否应该考虑任何安全问题?请注意,我(显然)只想为管理员用户提供此功能,而我们的管理员用户无论如何都可以完全访问源代码、数据库等,所以它并不是真正的“后门”;它只是让更容易访问用户的帐户。

【问题讨论】:

  • 是的,它是一个后门。如果你能破解这个功能,你就可以冒充任何人。此外,它还允许管理员像用户一样进行编辑,这样编辑在日志中显示为用户,而实际上它是另一个用户,等等。
  • Django 管理员无论如何都可以从管理界面编辑任何内容。正如我所说,我们的管理员可以完全访问源代码、数据库、服务器等。如果他们想代表用户做某事,他们可以使用纯 SQL 来完成。所以我真的不明白提供一种更友好的方式是多么危险。
  • 另外,请注意,我们在金融/银行/任何法规实际上可能合法地阻止我们这样做的行业。我们只是提供我们提供的服务,我们希望尽可能顺利地为客户提供支持。而已。 :)
  • 使用我在下面发布的这段代码,管理员不能做任何事情,并使其“看起来像另一个用户做了”。模拟仅适用于 GET 请求。它仅用于调试页面在某些异常情况下呈现的方式。为了模拟动作,我总是可以写一个单元测试。
  • 这不是一个安全漏洞,而且非常有用。如果用户抱怨某些内容未正确呈现或权限不起作用,则冒充该用户通常是重现问题的最实用方法。在 unix 中,管理员可以执行此操作。这是同一件事。如果该功能仅限于“超级”管理员,这是完全合理的,但当然必须像使用任何管理员功能一样谨慎使用。

标签: python django impersonation


【解决方案1】:

进行设置,使您在同一台服务器上拥有两个不同的主机名。例如,如果您在本地执行此操作,则可以使用 127.0.0.1 或 localhost 进行连接。您的浏览器会将其视为三个不同的站点,并且您可以使用不同的用户登录。这同样适用于您的网站。

因此,除了 www.mysite.com 之外,您还可以设置 test.mysite.com,并使用那里的用户登录。我经常设置站点(使用 Plone),所以我同时拥有 www.mysite.com 和 admin.mysite.com,并且只允许从那里访问管理页面,这意味着我可以使用具有问题。

【讨论】:

  • 这不能回答我的问题。我不想用不同的用户登录,因为我不知道其他用户的密码。我只想冒充其他用户(作为管理员)。
  • @ibz:不,你没有。那将是有史以来最大的安全漏洞,这是一个非常糟糕的主意。如果您确实对某个特定用户(而不是特定安全组)有问题,请重置该用户密码,并让用户稍后将其重置。
  • “安全漏洞”到底是怎么回事?
  • 说实话,我想我都在对这个问题的评论中回答了这个问题,而且我也认为这是不言而喻的。对不起。
  • @ibz:知道管理员密码意味着所有用户帐户都受到了威胁。而只知道一个用户密码只会危及一个帐户。
【解决方案2】:

我用一个简单的中间件解决了这个问题。它还处理重定向(即,在重定向期间保留 GET 参数)。这里是:

class ImpersonateMiddleware(object):
    def process_request(self, request):
        if request.user.is_superuser and "__impersonate" in request.GET:
            request.user = models.User.objects.get(id=int(request.GET["__impersonate"]))

    def process_response(self, request, response):
        if request.user.is_superuser and "__impersonate" in request.GET:
            if isinstance(response, http.HttpResponseRedirect):
                location = response["Location"]
                if "?" in location:
                    location += "&"
                else:
                    location += "?"
                location += "__impersonate=%s" % request.GET["__impersonate"]
                response["Location"] = location
        return response

【讨论】:

  • 如果您可以轻松打开和关闭此中间件(当然是通过文件系统配置),那么这是一个很好的折衷方案,因为您可以将其关闭,除非您真的需要它。
  • 他没有理由对这个功能如此偏执。管理员可以删除用户。管理员可以编辑用户。管理员可以杀死该站点。以他们身份登录同样安全。只要超级管理员登录是安全的,“Su”功能也是如此。如果对管理员有疑虑,可以记录会话被取消的事实,以便事件可追踪。
  • 我应该补充一点,我经常包含此功能。它非常有用。如果这是一个银行网站,我会使用一些非常明确和可见的日志记录,并且严格限制超级管理员的权限,但即使有适当的保护措施也很好。
  • 我使用了类似的中间件,但使用了自定义标头。 X-伪装成:。然后在请求中设置用户属性,同时将超级用户设置为“real_user”,然后在日志记录中使用。
【解决方案3】:

我看不出这是一个安全漏洞,而不是在 unix 机器上使用 su - someuser 作为 root 用户。如果他/她愿意,root 或具有对数据库的 root/admin 访问权限的 django-admin 可以伪造任何东西。风险仅在于 django-admin 帐户被破解,此时破解者可以通过成为另一个用户然后伪装成该用户的操作来隐藏轨迹。

是的,它可能被称为后门,但正如 ibz 所说,管理员无论如何都可以访问数据库。能够根据这种情况对数据库进行更改也是一个后门。

【讨论】:

  • 好吧,原则上 Unix 的安全性已经被严重破坏了。不同之处在于,经过 40 年的 unix 错误修复,很难破解 su 命令并执行 su ,除非你应该这样做。成千上万的人试图打破它,成千上万的人已经解决了问题。 ibz Django 中间件几乎不是这种情况。如果你想安全,你必须变得偏执。 :)
  • 但是,一旦你是 su-capable 用户(在 unix 下),你可以做任何事情。与设置 is_superuser 标志相同。只要模拟中间件检查这个标志,那么它就和通过管理员做某事一样安全。
【解决方案4】:

我还没有足够的声誉来编辑或回复(我认为),但我发现虽然 ionaut 的解决方案在简单的情况下有效,但对我来说更强大的解决方案是使用会话变量。这样,即使 AJAX 请求也能正确处理,而无需修改请求 URL 以包含 GET 模拟参数。

class ImpersonateMiddleware(object):
    def process_request(self, request):
        if request.user.is_superuser and "__impersonate" in request.GET:
            request.session['impersonate_id'] = int(request.GET["__impersonate"])
        elif "__unimpersonate" in request.GET:
            del request.session['impersonate_id']
        if request.user.is_superuser and 'impersonate_id' in request.session:
            request.user = User.objects.get(id=request.session['impersonate_id'])

用法:

log in: http://localhost/?__impersonate=[USERID]
log out (back to admin): http://localhost/?__unimpersonate=True

【讨论】:

  • 谢谢,这很好用!我只是将其更改为对用户名而不是 id 进行操作,因为这对我们更有意义。
【解决方案5】:

看起来很多其他人都遇到了这个问题,并编写了可重用的应用程序来解决这个问题,至少有一些在django packages page for user switching 中列出。在撰写本文时最活跃的似乎是:

  • django-hijack 在管理员的用户列表中放置一个“劫持”按钮,并在页面顶部放置一个用于劫持帐户的按钮。
  • impostor 表示您可以使用用户名“me as other”和您自己的密码登录
  • django-impersonate 设置 URL 以开始模拟用户、停止、搜索等

【讨论】:

  • django-hijack 让我很开心。感谢 @hamish 推荐这些软件包。
【解决方案6】:

@Charles Offenbacher 的回答非常适合模拟未通过令牌进行身份验证的用户。但是,它不适用于使用令牌身份验证的客户端应用程序。要让用户模拟使用令牌与应用程序一起工作,必须直接在模拟中间件中设置 HTTP_AUTHORIZATION 标头。我的回答基本上抄袭了查尔斯的回答,并添加了手动设置上述标题的行。

class ImpersonateMiddleware(object):
    def process_request(self, request):
        if request.user.is_superuser and "__impersonate" in request.GET:
            request.session['impersonate_id'] = int(request.GET["__impersonate"])
        elif "__unimpersonate" in request.GET:
            del request.session['impersonate_id']
        if request.user.is_superuser and 'impersonate_id' in request.session:
            request.user = User.objects.get(id=request.session['impersonate_id'])
            # retrieve user's token
            token = Token.objects.get(user=request.user)
            # manually set authorization header to user's token as it will be set to that of the admin's (assuming the admin has one, of course)
            request.META['HTTP_AUTHORIZATION'] = 'Token {0}'.format(token.key)

【讨论】:

    猜你喜欢
    • 2012-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-12
    • 2021-12-11
    • 1970-01-01
    • 2019-03-30
    • 1970-01-01
    相关资源
    最近更新 更多