【问题标题】:ASP.NET MVC Anti Forgery Token InsecureASP.NET MVC 防伪令牌不安全
【发布时间】:2014-04-26 12:16:27
【问题描述】:

在没有ssl的情况下向服务器发出请求时,我实际上可以看到MVC3框架生成的纯文本验证令牌密钥。

此密钥存储在名为:_RequestVerificationToken_Lw__ 的 cookie 中

在混合安全环境中,实际上可以在对非 ssl 站点的初始请求中看到以纯文本形式发送到服务器的此令牌。此令牌在用户会话期间也是静态的。那么拥有这个令牌有什么用,因为它很容易被攻击者窃取,因为 cookie 会以纯文本形式到处乱扔。

不应该将此 cookie 标记为安全且永远不会以纯文本形式发送吗?或者至少在每次请求时都重新生成,这样安全信息就不会从 ssl 通道中泄露出来?

我说的是 MVC 3 AntiForgeryWorker 类中的这个块

private string GetAntiForgeryTokenAndSetCookie(HttpContextBase httpContext, string salt, string domain, string path)
{
  string forgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(httpContext.Request.ApplicationPath);
  AntiForgeryData token = (AntiForgeryData) null;
  HttpCookie httpCookie = httpContext.Request.Cookies[forgeryTokenName];
  if (httpCookie != null)
  {
    try
    {
      token = this.Serializer.Deserialize(httpCookie.Value);
    }
    catch (HttpAntiForgeryException ex)
    {
    }
  }
  if (token == null)
  {
    token = AntiForgeryData.NewToken();
    string str = this.Serializer.Serialize(token);
    HttpCookie cookie = new HttpCookie(forgeryTokenName, str)
    {
      HttpOnly = true,
      Domain = domain
    };
    if (!string.IsNullOrEmpty(path))
      cookie.Path = path;
    httpContext.Response.Cookies.Set(cookie); //Ma, Why isn't this marked as "SECURE"
  }
  return this.Serializer.Serialize(new AntiForgeryData(token)
  {
    Salt = salt,
    Username = AntiForgeryData.GetUsername(httpContext.User)
  });
}

【问题讨论】:

  • 您能否提供一个重现该问题的最小示例?
  • 不确定您要查找的示例,该框架应该自行转储此令牌。但以防万一,上面有问题的代码块。
  • cookie 设置为 'HttpOnly',所以它不是不安全的。
  • 不应该是安全的吗?我的意思是,否则中间的人可以拥有这个 cookie 并发起 CSRF 攻击。或者至少应该根据请求轮换该值,但事实并非如此。
  • 对我来说,每次请求都会重新生成新令牌。

标签: asp.net asp.net-mvc asp.net-mvc-3 security csrf


【解决方案1】:

为了防止 CSRF 攻击,最佳解决方案是始终使用 SSL。如果没有 SSL,是的,nonce——正如它所说的——很容易受到 MITM 攻击。使用 cookie 存储 nonce 时,cookie 必须 标记为仅 HTTP。这可以防止 JavaScript 读取 cookie。除了 cookie 之外,您还应该将 nonce 呈现为所有 <form>s 中的 <input type="hidden" value="nonce"> 标记。

任何有权访问浏览器本身的人都可以读取 nonce,而防止重放攻击的唯一方法是让 nonce 在服务器第一次验证后第一次过期。但是,当用户使用后退按钮并使用相同的 nonce 重新提交请求时,这种方法可能会导致糟糕的用户体验。因为您使用的是 ASP.NET MVC 的内置反 CSRF 保护机制,所以将其行为更改为只允许使用一次 nonce 可能并不容易。 (编辑:感谢下面的 Levi 告诉我 ASP.NET MVC 实际上使这变得非常简单)

如果您想更好地控制随机数的生成和验证,那么我建议滚动您自己的实现,就像我在 JuniorRoute 框架中所做的那样。事实上,随意看看JuniorRoute's source code 看看我是如何实现它的。 Stack Overflow 帖子的代码太多了。

【讨论】:

  • 它实际上并不需要标记为 HttpOnly - 一些 JavaScript 框架可以使用 double submit cookies 技术作为将 cookie 值包含为隐藏表单字段的简单方法(或作为请求标头)。我建议设置 Secure 标志以防止通过普通 HTTP 传输。
【解决方案2】:

这就是你的问题标题。

内置的 MVC 防伪功能与应用程序的配置一样安全。如果在 Web.config (see MSDN docs) 中设置了<httpCookies requireSSL="true" />,则写入 Response.Cookies 的所有 cookie 将自动标记为“安全”修饰符。如果设置了此开关,MVC 的防伪 cookie 也会获得此行为。

在您的回复中将此功能与setting the HSTS header 等其他功能结合使用,您实际上是在保证浏览器永远不会通过纯文本通道发送敏感数据。

此外,防伪系统确实允许在令牌中存储自定义数据,并且您可以在令牌验证时收到回调以验证自定义数据。请参阅AntiForgeryConfig.AdditionalDataProvider 了解更多信息。

【讨论】:

  • 太酷了!你可以看出我有一段时间没有使用过 ASP.NET MVC。微软很好地提供了这些钩子! :)
  • @Levi,这不是一个全有或全无的提议吗?出于性能原因,我们有一个混合安全站点。我们不打算通过 ssl 发送所有 cookie。只是我们认为“敏感”的那些。这个 CSRF 符合“敏感”的要求。即使有额外的数据提供者,也无法解决 cookie 可能通过非安全通道传输的事实,除非您认为我应该自己处理加密。
  • 多年前 SSL 曾经很昂贵。这已不再是这种情况。完全 SSL 站点现在具有与混合安全站点相同的性能特征。不过,您可以使用 AntiForgeryConfig.RequireSSL 属性设置反 xsrf cookie 的“安全”标志,而无需选择所有内容:请参阅msdn.microsoft.com/en-us/library/… 了解更多信息。
  • @Levi 我检查了 AntiForgeryConfig.RequireSSL
  • 然后你可以挂钩 EndRequest,循环访问响应 cookie,并为每个你只想通过 SSL 发送的设置 Secure=true。许多其他方法来完成同样的事情。尽管到目前为止最好的解决方案是通过 SSL 运行整个站点并翻转 Web.config 中的主“所有 cookie 都应使用 SSL”开关。 (如果您的任何网站未通过 SSL 运行,攻击者仍然可以使用甚至会影响仅 SSL 页面的技巧。)
【解决方案3】:

我的看法

a) 提交的表单根据对比判断为非伪造

  • __RequestVerificationToken cookie &

  • __RequestVerificationToken 表单字段。

这两个值是某种对称匹配,因此不相同。

b) Cookie 永远不会被框架标记为默认的 must-use-secure-channel,因为某些应用程序不使用 https。

c) __RequestVerificationToken 实现是针对 CSRF 的保护,无法帮助有效用户窥探进程内存:p.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-09
    • 2015-01-11
    • 2015-03-12
    • 2014-10-03
    • 2022-08-16
    • 2014-01-23
    • 2016-10-25
    • 1970-01-01
    相关资源
    最近更新 更多