【问题标题】:How to protect cookies from an attack如何保护 cookie 免受攻击
【发布时间】:2011-10-02 08:50:47
【问题描述】:

我想在会话期间使用 cookie 来存储 userId,这样可以避免不必要的数据库往返。这个 userId 用于访问一些用户特定的信息。由于 cookie 可以很容易地编辑,我现在关心安全问题。

为了禁止已登录的用户编辑他们的 userId 并访问其他用户的信息,我使用了一种非常简单的方法。我在 userId cookie 创建时刻添加了一个 cookie,它存储了一个哈希值。在散列时,我使用硬编码的 64 字节密钥。从 cookie 中检索 userId 时,始终会检查它是否与其哈希值匹配。

这基本上是我的代码:

public static int GetUserId(Page page)
        {
            int userId;

            if (page.Request.Cookies["userId"] != null && page.Request.Cookies["userIdHashed"] != null)
            {
                string userIdHashed = page.Request.Cookies["userIdHashed"].Value;
                string userIdCoockie = page.Request.Cookies["userId"].Value;
                string coockie = (userIdCoockie + "945AFF2FD0F1D89B4B1DBEB1B0C5D3B8B5DCE000AAEA331EB0C3F3A68C3865EFA73BC6EBF30C8DF1AD6B9ECB7094DA5B0C1AF36B5BBD096E3D873E9589E3F664").GetHashCode().ToString();
                if (userIdHashed == coockie)
                {
                    userId = Int32.Parse(userIdCoockie);
                }
                else
                {
                    throw new Exception("UserId does not match!");
                }
            }

                else
                {

                    userId = ...//here userId is being retrieved from the data base and than:

                    page.Response.Cookies["userId"].Value = userId.ToString();
                    page.Response.Cookies["userId"].HttpOnly = true;
                string userIdHashed = (userId.ToString() + "945AFF2FD0F1D89B4B1DBEB1B0C5D3B8B5DCE000AAEA331EB0C3F3A68C3865EFA73BC6EBF30C8DF1AD6B9ECB7094DA5B0C1AF36B5BBD096E3D873E9589E3F664").GetHashCode().ToString();
                page.Response.Cookies["userIdHashed"].Value = userIdHashed;
                page.Response.Cookies["userIdHashed"].HttpOnly = true;
            }

            return userId;
        }

所以我的问题是:

  • 可以考虑这种方法吗 在这种情况下足够可靠吗?

  • 如果不应该修改它以及如何或 我应该寻找不同的东西吗 (例如通过加密/解密 System.Security.Cryptography 作为 推荐here)?

还有一个问题:设置 HttpCookie.HttpOnly = true 以防止 javascript 访问 cookie 是否真的有意义,因为它也可以很容易地被用户修改?

更新

非常感谢 Kerrek SB 和 Darin Dimitrov 的回答,他们认为我自己尝试保护 cookie 是没有意义的,因为已经内置了保护机制来存储此类信息。回发。

建议的选项是:

  • 使用 ASP.NET cache(但我相信它通常应该 存储应该在用户之间共享的信息,所以我看 其他两个选项)。
  • 将带有 userId 的自定义字符串添加到 UserData 部分 FormsAuthenticationTicket
  • 使用Session State

所以目前我正在后两者之间做出决定。

更改 FormsAuthenticationTicket 并不简单。此外,它不适用于无 Cookie 表单身份验证(如 here 所述)。

使用会话状态要容易得多,但它会影响性能,因为它将值存储在服务器内存中。然而,在我的情况下,它可能并不那么引人注目,因为我们只存储了 int 类型的 userId。

所以现在最后一个选项对我来说看起来好多了。但是,如果其他人可以评论和支持或批评所讨论的任何选项,我将不胜感激。

提前致谢!

【问题讨论】:

    标签: asp.net security session cookies session-state


    【解决方案1】:

    您还可以使用安全套接字层加密 cookie HttpCookie cookie = new HttpCookie(); cookie.Secure = true;

    【讨论】:

    • 感谢您的回答,但必须在应用程序中使用 SSL 才能使用 SSL cookie,这不是我的本意。
    • 设置cookie.Secure = true 不加密cookie,它只是告诉浏览器仅在使用安全通道时发送cookie。因此,如果将其设置为true,那么在使用 http 时根本不会发送 cookie。
    【解决方案2】:

    您似乎在这里重新发明了一些轮子。虽然在编写一些标准代码时这可能是可以接受的,但当涉及到安全性时,这几乎总是会导致灾难性的后果。

    要跟踪积极登录的用户,我建议您使用forms authentication(这里是另一个useful tutorial)。它使用身份验证 cookie 来跟踪用户。这些 cookie 由框架安全加密,因此无法使用服务器 machine.config 文件的 <machineKey> 部分修改它们。

    形成你的代码,你需要做的就是访问当前登录的用户名:

    public static string GetUserId(HttpContextBase context)
    {
        if (context == null || !context.User.Identity.IsAuthenticated)
        {
            return null;
        }
    
        return context.User.Identity.Name;
    }
    

    您真的不应该手动处理所有这些东西,尤其是当 ASP.NET 框架具有内置机制时。

    【讨论】:

    • 谢谢。实际上,我确实使用表单身份验证和会员资格。我在这里需要 cookie 不是为了跟踪登录用户,而是从数据库中检索用户特定信息,它存储在表中,此自定义 userId 作为外键。由于我之前的问题和相应的答案 (details here),我决定使用此模型。所以不幸的是,为了我的目的,以标准方式检索 Identity.Name 甚至是会员 guid UserName 是不够的。
    • @Kirill,在这种情况下使用custom profile,这将允许您存储有关当前登录用户的其他信息。
    • 如果我做对了,您建议使用自定义配置文件来存储我的自定义 userId。但是 afaik 配置文件功能没有与任何缓存集成,因此每个使用配置文件数据的请求都需要数据库连接。这正是我想要避免的。
    • @Kirill,你是对的。如果您想避免对每个请求进行数据库访问,您可以使用身份验证票证的userData 部分,您可以在其中存储自定义信息。这是一个很好的教程:man.ddvip.com/web/bsaspnetapp/LiB0057.html。在此示例中,他们将一些角色存储到其中,但您可以使用它来存储您喜欢的任何信息。它将被加密并成为身份验证 cookie 的一部分,并在每次请求时发送,因此可用。
    • 还有另一种可能性是使用 ASP.NET 缓存来存储此信息,以避免往返数据库。
    【解决方案3】:

    那是非常迂回和模糊的。如果您已经有一个活动会话,为什么不将这种数据(请注意,客户端永远不需要知道)存储在您的服务器端会话数据中?

    您需要与客户交换的只是会话 ID,真的。

    【讨论】:

    • 感谢您的回答。然而,它看起来像是一个常见的问题 cookie 与会话,例如 herehere 被广泛讨论。在大多数情况下,它最终取决于开发人员的个人偏好,尽管在这种特殊情况下您可能是对的,并且使用 session 比使用 cookie 更有优势。可能我会按照您的建议将模型更改为使用会话,但首先我想听听其他意见。
    • @Kirill:论据非常简单:您的数据库的 ID 字段值永远不需要用户知道。它与客户端行为无关。因此它自然属于服务器端。这是一个不应向用户公开的实现细节。
    • 顺便说一句,您的linked question 只是说明了社区处于多么糟糕的状态 - 问题本身就是比较苹果和梨,没有任何意义。它会询问“您是使用 cookie 还是使用会话状态来跟踪身份验证状态”,就好像它存在一样。什么是“会话状态”?您必须以某种方式在 HTTP 请求中识别会话状态。没有太多方法可以做到这一点,基本上是 cookie 或 URL 参数,但提问者似乎没有掌握这一点。
    • 确实如此,但本质上取决于您是否使用 cookie 或 URL 参数来存储 SessionID。这并不意味着在一般情况下会话是可取的。虽然正如我所说的那样,你可能是对的。
    • 你说得对,cookie 和 URL 参数之间的选择取决于你。 (虽然 URL 参数有这么多问题,以至于这已成定局。)没有意义的是询问是否“在 cookie 或会话中跟踪身份验证状态”......嗯,好的,好吧,您可以编写一个只接受&i_am_authenticated=1 并授予您完全访问权限的服务器。好吧,我没想到包括那个。很公平:-)
    猜你喜欢
    • 1970-01-01
    • 2020-05-12
    • 2016-10-28
    • 2018-09-08
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 2010-11-04
    • 1970-01-01
    相关资源
    最近更新 更多