tags:

views:

154

answers:

2

When should I enforce SSL for secure pages in an ASP.NET page life-cycle?

I mean should I do it inside page_load? or OnInit? or some other function?

I am using the following code to enforce SSL for certain pages, but where should I put this code? Earlier I placed it inside OnInit function, but that did not work well with ASP.NET wizards. Do I need to check whether it's postback or not first?

If postback drops https, shouldn't my code enforce it? If postback does not drop https, shouldn't my code stop redirecting and move to the next step of the wizard? It seems like it keeps redirecting.

 if (!HttpContext.Current.Request.IsSecureConnection) {
                HttpContext.Current.Response.Redirect(SiteNavigation.ResolveAbsoluteUrl(true, HttpContext.Current.Request.Url.PathAndQuery));
            }
+1  A: 

I usually do this in the OnPreLoad event to force SSL:

protected override void OnPreLoad(EventArgs e)
{
    base.OnPreLoad(e);
    String qs;
    qs = Request.QueryString;

    //// Force the page to be opened under SSL
    if (!Request.IsSecureConnection)
    {
        if (qs != "")
        {
            qs = "?" + qs;
        }

        Response.Redirect("https://" + 
        Request.ServerVariables["SERVER_NAME"].ToString() + 
        Request.ServerVariables["PATH_INFO"].ToString() + qs);
    }
}

If you want to force SSL for all pages, it may be a good fit for an HttpModule. I have come up with the following:

using System;
using System.Web;

namespace CustomHttpModules
{
    public class EnforceSSLModule : IHttpModule
    {
        public void Init(HttpApplication httpApp)
        {
            httpApp.PreRequestHandlerExecute += this.OnPreRequestHandlerExecute;
        }

        public void Dispose()
        {
        }

        public void OnPreRequestHandlerExecute(object o, EventArgs e)
        {
            using (HttpApplication httpApp = (HttpApplication)o)
            {
                if (HttpContext.Current != null)
                {
                    HttpContext ctx = HttpContext.Current;
                    String qs;

                    qs = ctx.Request.QueryString;

                    //// Force the page to be opened under SSL
                    if (ctx.Request.IsSecureConnection)
                    {
                        if (qs != "")
                            qs = "?" + qs;

                        ctx.Response.Redirect("https://" + 
                            ctx.Request.ServerVariables["SERVER_NAME"].ToString() + 
                            ctx.Request.ServerVariables["PATH_INFO"].ToString() + qs);
                    }
                }

            }

        }
    }
}

To use the HttpModule in IIS5.1 or IIS6, drop the compiled assembly for the HttpModule in your site's bin folder and add the following to your web.config's HttpModules section:

<add type="CustomHttpModules.EnforceSSLModule, dllname" name="EnforceSSLModule" />

(where dllname is the name of your assembly file without the extension)

Saul Dolgin
+1  A: 

You have basically two options.

If you want all authenticated pages to run under SSL, you can set the requireSSL="true" attribute on forms authentication. Just make sure your login page is also running on HTTPS.

You can also set this on a page-by-page basis. I found this works well in a "page base" class that inherits from System.Web.UI.Page, and that all your pages inherit from (instead of System.Web.UI.Page).

public class PageBase : System.Web.UI.Page
{
    public bool RequiresSSL {get; set;}
    string currentPage = Request.Url.ToString();

    public PageBase()
    {
         Init += new EventHandler(PageBase_Init);
    }

    void PageBase_Init(object sender, EventArgs e)
    {
            if ((RequiresSSL) && (WebConfigurationManager.AppSettings["SSLavailable"] == "true"))
            {
                if (currentPage.ToLower().StartsWith("http://"))
                {
                    redirectTo = "https://" + currentPage.Substring(7);
                    Response.Redirect(redirectTo);
                }
            }
            else
            {
                if (currentPage.ToLower().StartsWith("https://"))
                {
                    redirectTo = "http://" + currentPage.Substring(8);
                    Response.Redirect(redirectTo);
                }
            }
    }
}

The AppSettings value of SSLavailable allows you to switch the whole mechanism off when you're running in test mode without SSL.

For pages that need to run in SSL mode, all they need to do is set RequiresSSL:

public partial class ChangePassword : PageBase
{
    public ChangePassword()
    {
        PreInit += new EventHandler(ChangePassword_PreInit);
    }

    void ChangePassword_PreInit(object sender, EventArgs e)
    {
        RequiresSSL = true;
    }
}

It works, very smoothly, and any other pages they go to after the secure page will automatically switch back to HTTP protocol.

Cylon Cat