Asp.net MVC提供了大量(非常有用的)HtmlHelper
扩展。但是,如果我要提供一个扩展现有方法的扩展方法的微子框架呢?
即。 BeginForm
可能会被重写为更丰富(总是添加防伪令牌和类似的安全内容。
为了不重写Asp.net MVC的HTML帮助方法所有,如何强制使用我的?因此,使用通常的BeginForm
会抛出异常或者首先不可访问。如果不从视图的文件夹 web.config 文件中删除System.Web.Mvc.Html
命名空间,则可能无法进行第二种选择。这意味着那些帮助者的所有都需要重写。这是我不想做的事情。
问题在于,当使用这个微子框架时,出于安全原因应该防止使用标准帮助程序。周期。
还有哪些其他选择?
假设我只会编写自己的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
答案 0 :(得分: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视图的编译):
或运行时异常(如果还没有。)
答案 1 :(得分:0)
您正试图通过强制开发人员来避免使用Html.BeginForm
而不是使用受保护的安全性来实现应用程序的安全性。假设你以某种方式欺骗框架不要使用Html.BeginForm
那么什么?一个甚至不知道Html.BeginForm
的年轻开发人员可以直接在视图中编写表单HTML并破坏规则!
我认为安全性必须在应用程序中实现,不要强迫某人使用正确的工具,而是必须在应用程序的更高级别完成。在表单示例中,如果发布到服务器的所有HTML表单都应该具有防伪标记,那么我将在MVC管道中的更高级别进行检查。如果某些开发人员使用普通表单,那么该模块将无法工作,并且在测试阶段将会小心。