6

我正在努力提高我公司网站的安全性,并希望创建一个令牌来防止可以轻松维护的伪造尝试,这就是我想出的。

public class AntiForgeryToken
{
    private readonly string _referenceToken;

    public AntiForgeryToken()
    {
        _referenceToken = Guid.NewGuid().ToString();
    }
    public string ReferenceToken
    {
        get { return _referenceToken; }
    }
}

在我的 MasterPage 的基类中,我有一个 HiddenField,其中包含名为:ReferenceToken

protected virtual void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        InjectToken();
    }

    ValidateToken();
}

private void InjectToken()
{
    var token = ObjectFactory.GetInstance<AntiForgeryToken>();
    ReferenceToken = token.ReferenceToken;
}

private void ValidateToken()
{
    var token = ObjectFactory.GetInstance<AntiForgeryToken>();
    if (ReferenceToken.Equals(token.ReferenceToken, SC.InvariantCultureIgnoreCase)) 
            return;
    ...do stuff for failed token
}

我有 StructureMap 句柄将令牌存储在 Session 中,因此它在每个用户会话中都保持不变,所有这些都是 AntiForgery 方案的有效实现吗?

编辑:我的问题似乎有些混乱,是的,我了解 ASP.NET MVC 有一个内置的 AntiForgeryToken 方案,这个问题明确地是关于如何为WebForms重新创建它以防止使用 CSRF 攻击(Cross Site Request Forgery )。我理解这绝不会消除对用户权限的适当授权的需要。

我将提出@Neal 和@solairaja 发布的链接:使用 ASP.NET MVC 的 AntiForgeryToken() 帮助程序防止跨站点请求伪造 (CSRF)。本文解释了更多 CSRF 攻击是什么以及 MVC 如何阻止它,但是他们的解决方案不适用于 Web 表单,这就是我开始实施自己的解决方案的原因。

在看到@Neal 的回复后,我认为这很可能是公认的答案,因为我没有意识到我可以从 MVC 工具中获取实际源代码,这很可能会取代 guid 创建。但如果其他人有一些有价值的信息要添加,我会留下这个问题。

4

8 回答 8

4

克里斯,

您的方法或多或少模仿了 MVC 中的防伪方法,除了它们使用从 RNGCryptoServiceProvider 生成的 base64 编码字节数组并将令牌存储在页面(隐藏表单字段)和 cookie 中。我建议将更多的逻辑移动到令牌实现中(例如,将大部分验证逻辑封装在令牌内)。

MVC 实现的代码可在http://aspnet.codeplex.com/sourcecontrol/changeset/view/23011?projectName=aspnet#391757上免费访问,如果可能的话,您可能应该查看它以及http://blog.codeville .net/2008/09/01/prevent-cross-site-request-forgery-csrf-using-aspnet-mvcs-antiforgerytoken-helper/进行分析 + 想法。

于 2009-11-17T00:45:24.110 回答
2

如果您使用 View State,则 ASP.NET Web 窗体默认情况下会立即阻止 CSRF 攻击。除非您在应用程序中有效地禁用了视图状态,否则您正在添加代码来解决您没有的问题。

View State 防止 CSRF 攻击
.Net CSRF Guard - OWASP

于 2010-12-16T14:42:33.507 回答
0

首先,我想我应该问......你所说的“AntiForgery”到底是什么意思?你担心被伪造什么?接下来的其余部分只是一些浮现在脑海中的一般信息......

我要改变的一件事是不使用 Guid.NewGuid。关于它是否是随机的,因此不适合安全目的存在争议。也就是说,我认为这将是一次非常艰难的进攻。

查看 RNGCryptoServiceProvider 的 GetBytes 方法,以了解更适合生成随机令牌的方法。除了更好的随机性之外,另一个优点是您可以将其设置为任何您想要的大小。

你是通过 ssl 做的吗?首先,ssl 是中间人攻击的第一道防线。它可能不足以满足所有需求(其他人可以对此进行辩论),但如果您担心这些事情,那么它就是起点。如果不是,你如何确保你得到的是来自正​​确机器的响应,而不是首先响应的中间人?如果没有 SSL 或等效项,您的令牌就像您所做的任何其他事情一样容易被盗。

要考虑添加的另一件事是让您的代币仅适用于一次旅行,并且您在下次旅行时生成一个新的代币返回给客户。试图重用它失败了。

如果这是您的想法,我不会尝试用您自己设计的其他东西替换 SSL。但是,如果您担心重放,则生成一次令牌是阻止它的一种方法。如果您担心用户两次提交相同的表单数据,这是一回事。如果您对此感到担忧,我也会考虑您的整体应用程序设计。许多重播和类似场景可能会被您的业务逻辑的合理设计所击败,例如不信任客户端向您发送敏感信息,例如购物车中商品的价格。

还请查看有关 ASP.NET 和 IIS 安全的各种 Microsoft 指南(即 Google ASP.NET 或 IIS 安全站点:microsoft.com)作为起点。很多聪明人已经为我们解决了很多问题。

于 2009-11-12T21:39:01.087 回答
0

所有这些都是防伪方案的有效实现吗?

据我所知,您似乎正在将 GUID 插入页面,然后在页面返回时查找相同的 GUID。

我不知道你的要求是什么,所以我不能说这个方案是否真的“有效”。不过,我可以指出几点:

  1. 如果 GUID 只存在于页面上,那么什么会阻止用户在一台机器上阅读页面并从另一台机器提交表单?如果您还没有将其与 cookie 或会话(也使用 cookie)相关联,那就太好了。
  2. 如果 GUID 作为静态隐藏字段写入页面<input>,则机器人可以读取和提交表单。您可以通过在提交之前要求页面上的脚本处理令牌来解决此问题。
  3. 你在使用 ViewState 吗?如果是这样,您可能会考虑仅设置ViewStateUserKey为每个客户唯一的可重复值;它执行与您在此处描述的功能类似的功能。
于 2009-11-15T14:42:20.560 回答
0

正如 NICK 所说,对我来说,您提供的代码看起来就像您正在将 GUID 插入页面,然后在页面返回时寻找相同的 GUID。当您使用存储到会话中的结构映射时,这也是个好主意。

但是有一些内置方法可用于此 AntiForgery 概念。

请先参考以下链接了解

http://blog.maartenballiauw.be/post/2008/09/01/ASPNET-MVC-preview-5s-AntiForgeryToken-helper-method-and-attribute.aspx

现在,

检查以下链接以获取详细说明和接近方法。

http://msdn.microsoft.com/en-us/library/system.web.mvc.htmlhelper_methods.aspx

http://blog.codeville.net/2008/09/01/prevent-cross-site-request-forgery-csrf-using-%20aspnet-mvcs-antiforgerytoken-helper/

谢谢 !!

于 2009-11-17T05:49:24.867 回答
0

在我看来,它好像在为每个请求生成一个金丝雀。现在如果用户打开多个标签会发生什么?:)

您的方法(以及 ASP.NET MVC 实现)的问题在于它依赖于开发人员来实现它。像这样的安全应该是选择退出,而不是选择加入。当我编写一个AntiCSRF 模块时,我最终改用了 ASP.NET 页面生命周期,这意味着不会更改底层代码,除非开发人员想要选择一个页面退出 CSRF 检查。您会注意到它使用了一个令牌,该令牌在该用户的浏览器会话的整个生命周期内都持续存在 - 实际上不需要在每个请求中更改令牌。

现在我编写这个模块主要是为了说明我即将出版的书的一些概念(在此处插入广告grin),您当然可以使用ViewStateUserKey,但这也是选择加入,而不是选择退出。

于 2009-11-17T14:46:31.993 回答
-1

第一条安全规则:不要试图推出自己的安全性

据我了解您的描述,这不是一个有效的防伪方案。攻击者只需要使用浏览器的“查看源代码”功能来查找令牌即可绕过它。然后,只要他们记得发布该令牌,他或她就可以发布他们喜欢的任何内容,并且您的代码不会知道其中的区别。

抱歉,如果我完全误解了您的描述...

于 2009-11-10T08:10:02.040 回答
-1

我不会使用这样的防伪令牌,而是验证经过身份验证的用户实际上是否具有进行请求修改的必要权限。

例如,网页是“创建用户页面”,我会检查经过身份验证的用户是否有权创建新用户。该页面是否为“编辑用户 X 页面”,我会检查经过身份验证的用户是否有权修改用户 X。可能是因为他本人是用户 X,或者是管理用户。

也就是说,使用 GUID 不是很安全。Guid 是基于为唯一性而非随机性而编写的算法生成的。AFAIK 有三种有效的算法,基于名称的、基于时间的和随机的。如果系统使用的 Guid 算法(可能会被未来的 .NET 版本更改)是基于时间的,那么猜测有效的 Guid 并不是很困难。

于 2009-11-17T11:12:06.390 回答