0

Asp.net MVC 提供了很多(并且非常有用的)HtmlHelper扩展。但是,如果我要提供一个带有一些扩展方法的微型子框架来扩展现有的方法呢?

即可BeginForm能被重写为更丰富(总是添加防伪令牌等安全内容。

问题

为了不重写所有Asp.net MVC 的 HTML 辅助方法,我该如何强制使用我的方法?这样使用通常BeginForm会引发异常或首先无法访问。System.Web.Mvc.Html如果不从视图的文件夹web.config文件中删除命名空间,第二个选择可能是不可能的。这意味着所有这些助手都需要重写。这是我不想做的事情。

问题是,当使用这个微型子框架时,出于安全原因,它应该防止使用标准助手。时期。

我还有哪些其他选择?

例子

假设我只会写我自己的BeginForm,我会打电话BeginSecureForm,所以有人会把它用作:

@using Html.BeginSecureForm() {
    ...
    @Html.EditorFor(m => m.Something)
    ...
}

如您所见,我也使用了自定义助手和标准EditorFor助手。这意味着System.Web.Mvc.Html仍然包含使用非自定义帮助器,如EditorFor.

只要您使用我的自定义帮助方法,上面的代码就可以正常工作......但是如果一些开发人员忘记这样做并使用正常的方法怎么办?

@using Html.BeginForm() {
    ...
    @Html.EditorFor(m => m.Something)
    ...
}

那么在这种情况下,我要么想:

  • Html.BeginForm根本无法访问
  • Html.BeginForm抛出应该使用安全版本的异常
  • 可以做任何其他我不知道的事情来防止使用标准BeginForm
4

2 回答 2

1

实现这一目标的一种可能性是编写自定义WebViewPage并使用自定义覆盖Html属性:

public abstract class MyWebViewPage<T> : WebViewPage<T>
{
    public override void InitHelpers()
    {
        this.Ajax = new AjaxHelper<T>(ViewContext, this);
        this.Html = new MyHtmlHelper<T>(ViewContext, this);
        this.Url = new UrlHelper(ViewContext.RequestContext);
    }

    public new MyHtmlHelper<T> Html { get; set; }
}

这是自定义MyHtmlHelper<T>类,您将在其中废弃您不希望开发人员直接使用的方法:

public class MyHtmlHelper<T>: HtmlHelper<T>
{
    public MyHtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer)
        : base(viewContext, viewDataContainer)
    {
    }

    [Obsolete("Use SecureBeginForm instead", true)]
    public MvcForm BeginForm()
    {
        throw new Exception("Use SecureBeginForm instead.");
    }
}

好的,现在剩下要做的就是切换应用程序中所有 Razor 视图的基本类型。这可以~/Views/web.config在您将替换的地方完成:

<pages pageBaseType="System.Web.Mvc.WebViewPage">

和:

<pages pageBaseType="MyAppName.Mvc.MyWebViewPage">

好的,现在您可以将微框架扩展方法写入MyHtmlHelper类,从而提供默认方法的自定义安全对应物:

public static class MyHtmlHelperExtensions
{
    public static MvcForm SecureBeginForm<T>(this MyHtmlHelper<T> html)
    {
        var rawUrl = html.ViewContext.HttpContext.Request.Url.AbsoluteUri;
        var builder = new UriBuilder(rawUrl);
        builder.Scheme = Uri.UriSchemeHttps;
        var form = new TagBuilder("form");
        form.Attributes["action"] = builder.ToString();
        form.Attributes["method"] = "post";

        html.ViewContext.Writer.Write(form.ToString());
        return new MvcForm(html.ViewContext);
    }
}

现在在任何 Razor 视图中:

@using (Html.SecureBeginForm())
{
    ...
}

当你尝试:

@using (Html.BeginForm())
{
    ...
}

您会收到编译时错误(假设您已启用 Razor 视图的编译):

在此处输入图像描述

或者运行时异常,如果你没有。

于 2012-06-14T09:44:52.263 回答
0

您正试图通过强制开发人员避免使用Html.BeginForm而不是使用安全的来实现应用程序的安全性。假设您以某种方式欺骗了框架不使用,那又Html.BeginForm如何?一个甚至不知道的年轻开发者Html.BeginForm可以直接在视图中编写表单 HTML 并打破规则!

我认为安全性必须通过不强迫某人使用正确的工具而不是必须在应用程序的更高级别完成来在应用程序中实现。在表单示例本身中,如果发布到服务器的所有 HTML 表单都应该具有防伪令牌,那么我将在 MVC 管道中的更高级别进行检查。如果某些开发人员仍然使用正常形式,该模块将无法工作,并且将在测试阶段进行处理。

于 2012-06-14T09:48:15.057 回答