【问题标题】:ASP.NET MVC - HTML.BeginForm and SSLASP.NET MVC - HTML.BeginForm 和 SSL
【发布时间】:2010-06-19 18:08:50
【问题描述】:

我遇到了一个问题,应该是 ASP.NET MVC 2 中的简单登录表单。基本上我的表单看起来有点像这样:

using (Html.BeginForm("LogOn", "Account", new { area = "Buyers" }, FormMethod.Post, new { ID = "buyersLogOnForm" }))

我在 LogOn Action 方法上有一个 RequiresHTTPS 过滤器,但是当它执行时我收到以下消息

请求的资源只能是 通过 SSL 访问

此时唯一可行的解​​决方案是传入一个额外的操作 htmlattribute,如下所示:

 var actionURL = "https://"  + Request.Url.Host + Request.Url.PathAndQuery;   
 using (Html.BeginForm("LogOn", "Account", new { area = "Buyers" }, FormMethod.Post, new { ID = "buyersLogOnForm", @action = actionURL }))

虽然这可行,但我想知道 a) 为什么我首先会看到这个问题,以及 b) 是否有更直接的方式从 http 页面发布到 https?

[编辑]

我应该声明登录下拉菜单将在许多公共页面上可用。我不希望我的所有页面都是 HTTPS。例如,我的希望页面——任何人都可以看到——不应该是基于 HTTPS 的。本质上,我需要在我的表单中指定协议,但不知道该怎么做,或者是否可能。

如果有任何意见/建议,我将不胜感激。 提前致谢

日本

【问题讨论】:

    标签: c# asp.net-mvc ssl


    【解决方案1】:

    你可以使用

    <form action =" <%= Url.Action(
    "action",
    "controller",
    ViewContext.RouteData.Values,
    "https"
    ) %>" method="post" >
    

    【讨论】:

    • 这个问题是没有为您的表单创建 FormContext,因此所有 Html 输入助手都不会添加附加到您的视图模型的验证属性...
    • 请参阅下面 Brad J 的答案。这不安全!
    【解决方案2】:

    在呈现表单的操作和您要发布到的操作上都使用[RequireHttps] 属性。

    【讨论】:

    • 登录下拉菜单将在许多公共页面上可用。我不希望我的所有页面都是 HTTPS。例如,我的希望页面 - 任何人都可以看到 - 不应该基于 HTTPS
    • 可能会劝阻用户在浏览器中看不到挂锁的登录页面上输入用户名和密码。在登录页面上使用 HTTPS 被认为是一种很好的做法。
    • 我绝对明白你的意思。但是,我认为这是一个设计决定,不一定是技术限制。以 Twitter 为例,这种下拉菜单(来自非 https 页面)增强了用户登录体验 - 不需要两个简单字段的完整页面加载。
    • @DarinDimitrov:我刚刚看了RequireHttps的代码。其中有一个if (filterContext.HttpContext.Request.HttpMethod != "GET") throw new InvalidOperationException();。所以我不认为你真的需要/不想把它放在 POST 方法上......
    【解决方案3】:

    更新:在考虑使用此代码之前,请查看以下有关此方法的安全漏洞的 cmets。

    我发现 JP 和 Malcolm 的代码示例的混合工作。

    using (Html.BeginForm("Login", "Account", FormMethod.Post, new { @action = Url.Action("Login","Account",ViewContext.RouteData.Values,"https") }))
    

    尽管如此,我还是觉得有点 hacky,所以我创建了一个自定义 BeginForm 助手。自定义助手更干净,在本地运行时不需要 https。

    public static MvcForm BeginFormHttps(this HtmlHelper htmlHelper, string actionName, string controllerName)
        {
            TagBuilder form = new TagBuilder("form");
            UrlHelper Url = new UrlHelper(htmlHelper.ViewContext.RequestContext);
    
            //convert to https when deployed
            string protocol = htmlHelper.ViewContext.HttpContext.Request.IsLocal == true? "http" : "https";
    
            string formAction = Url.Action(actionName,controllerName,htmlHelper.ViewContext.RouteData.Values,protocol);
            form.MergeAttribute("action", formAction);
    
            FormMethod method = FormMethod.Post;
            form.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
    
            htmlHelper.ViewContext.Writer.Write(form.ToString(TagRenderMode.StartTag));
    
            MvcForm mvcForm = new MvcForm(htmlHelper.ViewContext);
    
            return mvcForm;
        }
    

    示例用法:

    @using (Html.BeginFormHttps("Login", "Account"))
    

    【讨论】:

    • 这样做真的不安全。在这个时代没有理由所有页面都不能是https。
    • 您能否详细说明为什么这不安全?
    • 因为它容易受到中间人攻击。未加密的页面可能会在传输过程中受到破坏,并且 URL 会被修改为指向其他人的站点。因为用户看不到您发布到的 url,所以用户无法知道发生了这种情况。这是一个例子resources.infosecinstitute.com/mitm-using-sslstrip
    • 感谢您的解释。我同意,这不是一种安全的做法。我在答案的顶部添加了警告。
    • @ErikFunkenbusch 我们网站中的所有页面都不能是 https。我们使用的远程内容并不都是安全的。因此,我们仅在需要时才使用 https,例如会员和结帐页面。
    猜你喜欢
    • 1970-01-01
    • 2010-11-03
    • 1970-01-01
    • 2021-11-01
    • 2011-12-14
    • 2018-04-01
    • 2014-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多