12

I am encountering an issue with what should be a simple logon form in ASP.NET MVC 2. Essentially my form looks a little something like this:

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

I have a RequiresHTTPS filter on the LogOn Action method but when it executes I receive the following message

The requested resource can only be accessed via SSL

At this point the only solution that worked was to pass in an extra action htmlattribute as follows:

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

While this works I wonder a) why i am seeing this issue in the first place and b) if there is a more straightforward way of posting to https from a http page?

[Edit]

I should have stated that the logon dropdown will be available on many public pages. I do not want all of my pages to be HTTPS. For instance, my hope page - which ANYONE can see - should not be HTTPS based. Essentially I need to specify the protocol in my form but have no idea how to do that, or if it is possible.

I would appreciate any advice/suggestions. Thanks in advance

JP

3 Answers 3

11

You could use

<form action =" <%= Url.Action(
"action",
"controller",
ViewContext.RouteData.Values,
"https"
) %>" method="post" >
Sign up to request clarification or add additional context in comments.

2 Comments

The issue with this is that there is no FormContext created for your form, so all of the Html input helpers wont add validation attributes attached to your view models...
See the answer below by Brad J. This is NOT secure!
6

Use the [RequireHttps] attribute on both the action that renders the form and the one you are posting to.

4 Comments

The logon dropdown will be available on many public pages. I do not want all of my pages to be HTTPS. For instance, my hope page - which ANYONE can see - should not be HTTPS based
Users might be dissuaded to enter their username and password on a login page on which the padlock is not visible in their browser. It is considered good practice to use HTTPS on logon pages.
I definitely see your point. However, I believe this to be a design decision and not necessarily something that should be a technical constraint. Take Twitter as an example of where such a dropdown (from a non https page) enhances the user login experience - not requiring a full page load for two simple fields.
@DarinDimitrov: I've just looked at the code of RequireHttps. There's a if (filterContext.HttpContext.Request.HttpMethod != "GET") throw new InvalidOperationException(); in it. So I don't think you actually need/want to put it on the POST method...
5

Update: Review the comments below about the security vulnerabilities of this approach before considering the use of this code.

I found that a hybrid of JP and Malcolm's code examples worked.

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

Still felt a bit hacky though so I created a custom BeginForm helper. The custom helper is cleaner and does not require https when running locally.

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;
    }

Example usage:

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

6 Comments

It's really not secure to do this. There is no reason in this day and age that all pages can't be https.
Can you expand on why this is not secure?
Because it's vulnerable to a man-in-the-middle attack. The unencrypted page can be compromised in transit and the url modified to point to someone elses site. Because the user cannot see the url that you are posting to, there is no way for the user to know that this has happened. Here's an example resources.infosecinstitute.com/mitm-using-sslstrip
Thank you for explaining. I agree, it is not a secure practice. I added a warning to the top of my answer.
@ErikFunkenbusch All pages can't be https in our web sites. The remote contents that we use are not all secure. So we use https only if needed like member and checkout pages.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.