2

I have a requirement to allow users to change their passwords via a form in my asp.net MVC application. My first thought was to decorate the ChangePassword action with a RequireHttps attribute.

However, I still have to send the password unencrypted before the attribute kicks in and returns "The requested resource can only be accessed via SSL". This defeats the purpose, doesn't it?

I am sure I am just confused and RequireHttps is useful; I would like to know if there is a way to use RequireHttps to achieve my aim. Alternatively, I would like to know any other way to achieve it.

UPDATE:

I now have some options thanks to the answers below - I can load the password inputs in an iframe using https, meaning that any posts from it will be encrypted. Other wise I can set the protocol to https in the code that constructs the post url:

var url = '@Url.Action("changePassword", "Security", new { area = "" }, "https")'

I'm not sure which is better, but I'm going to try the second one - any comments welcome.

Kev
  • 2,656
  • 3
  • 39
  • 63
  • 1
    Make sure all links to that form start with https://? – Michael Dunlap Jan 03 '13 at 16:48
  • 2
    +1 @MichaelDunlap. Just require your website to be HTTPS from the very first moment it get's hit by a user and then don't worry about secure or insecure information... Your users would probably appreciate having all of their interaction with your website to be secure over the complex toggling back and forth you seem to be trying to do. – Gup3rSuR4c May 22 '14 at 00:44

3 Answers3

6

Your application cannot control whether SSL is enabled. This depends only on web server configuration. The only thing you can do is make sure your application does not trust data that was not encrypted on the wire. RequireHttps does just that. Actions decorated with this attribute will never processes data that was sent in plain text.

LeffeBrune
  • 3,441
  • 1
  • 23
  • 36
  • 2
    It's not just data, HTTP GET is redirected HTTPS GET and HTTP POST is rejected. See http://stackoverflow.com/a/9730131/502537 – RickAndMSFT Sep 30 '15 at 00:11
2

The real use case of the RequireHttpsAttribute is to enforce the https:// scheme only when authentication is requested. Not in all cases. The RequireHttpsAttribute only implements the OnAuthentication method of the IAuthenticationFilter interface.

As the OnAuthentication method is only called from within the InvokeAuthenticationFilters method, I wouldn't use the RequireHttpsAttribute attribute.

To properly enforce https:// on certain controllers or actions, I'd create my own attribute, based on ActionFilterAttribute:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class EnforceHttpsActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        if (new[] { "GET", "HEAD" }.Any(verb => String.Equals(filterContext.HttpContext.Request.HttpMethod, verb, StringComparison.OrdinalIgnoreCase))) ;
        {
            string url = "https://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
            filterContext.Result = new RedirectResult(url);
        }
    }
}

To enforce https:// for the whole site, you can get inspired by a web.config markup that I've used for *.azurewebsites.net instances of our sample app.

  <system.webServer>
    <rewrite>
      <rules>
        <rule name="HTTPS Redirect in Azure">
          <match url="(.+)" />
          <conditions>
            <add input="{HTTPS}" pattern="^OFF$" />
            <add input="{HTTP_HOST}" pattern="^(.+)\.azurewebsites.net(.*)$" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="SeeOther" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
jerone
  • 16,206
  • 4
  • 39
  • 57
Jan Lenoch
  • 79
  • 2
  • 8
1

Note: The [RequireHttps] attribute does not handle HEAD requests - and instead gives the exception, so certain spiders or pre-fetching tools will get an error if they attempt to hit your site.

It is best anyway to do something like this in IIS with the rewrite module.

    <rule name="Redirect to http" enabled="true" patternSyntax="Wildcard" stopProcessing="true">
        <match url="*" negate="false" />
        <conditions logicalGrouping="MatchAny">
            <add input="{HTTPS}" pattern="off" />
        </conditions>
        <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Found" />
    </rule>

Taken from here: https://blogs.technet.microsoft.com/dawiese/2016/06/07/redirect-from-http-to-https-using-the-iis-url-rewrite-module/

Important Tip: Don't forget to reinstall the rewrite module when migrating to a new server - the error you get if you forget is somewhat obtuse!

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689