Chris Roberts

Automatically switching to SSL in ASP.NET

• Posted in Programming

At first, it seems like quite a simple requirement - to automatically transfer a visitor to an SSL connection when they visit a certain area of our site (everything in the 'secure' folder in our case), and to transfer them back to a plain old HTTP connection when they leave.

Our initial implementation of this was a simple HTTP Module. This intercepted incoming HTTP requests for the '/secure/' folder and redirected the user to an HTTPS version of the same page. Conversely, if an HTTPS request comes in for a page which isn't in the '/secure/' folder, a redirect is issued to the HTTP version.

This appeared to work fine for quite a while. But - we started to have some problems with the release of IE8 and recent releases of Firefox. On visiting the site, it would appear that requests for WebResource.axd were still being issued over HTTP rather than HTTPS. This meant that our users started getting warning messages pointing out that some parts of the page were not being delivered securely.

If the user told the browser not to download these resources, the site just didn't work. WebResource.axd is, after all, responsible for delivering the JavaScript which makes the ASP.NET framework's 'magic' happen.

We resolved the problem in the end by adding another rule to the HTTP Module to also redirect HTTP requests for WebResource.axd to HTTPS. We also check the Referrer of the incoming request to make sure the user is coming from a secure page - otherwise, we'll end up serving up WebResource.axd over SSL every time.

The code for our HTTP Module is shown below:

Imports System.Web

Public Class URLRewrite
    Implements IHttpModule

    Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init
        AddHandler context.BeginRequest, AddressOf OnBeginRequest
    End Sub

    Public Sub Dispose() Implements System.Web.IHttpModule.Dispose

    End Sub

    Public Sub OnBeginRequest(ByVal Sender As Object, ByVal e As EventArgs)
        Dim App As HttpApplication = Sender
        Dim URI As String = App.Request.Url.AbsoluteUri

        ' Is the request for a 'secure' page, currently not secured?
        If (App.Request.Path.StartsWith("/secure/", StringComparison.OrdinalIgnoreCase) OrElse _
            (App.Request.Path.ToLower.Contains("webresource.axd") AndAlso App.Request.UrlReferrer.PathAndQuery.StartsWith("/secure/", StringComparison.OrdinalIgnoreCase))) AndAlso _
            (URI.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) Then
#If Not DEBUG Then
            ' Redirect to https...
            App.Response.Redirect("https" & URI.Remove(0, 4))
            App.Response.End()
#End If
        ElseIf (Not (App.Request.Path.StartsWith("/secure/", StringComparison.OrdinalIgnoreCase) OrElse _
            (App.Request.Path.ToLower.Contains("webresource.axd") AndAlso App.Request.UrlReferrer.PathAndQuery.StartsWith("/secure/", StringComparison.OrdinalIgnoreCase)))) AndAlso _
            (URI.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) Then

            ' Redirect to http...
            App.Response.Redirect(URI.Remove(4, 1))
            App.Response.End()
        End If

    End Sub
End Class

Once registered in the web.config, the module will start working its magic. Note that we don't issue redirects if the site is built for DEBUG. This allows us to test the site in our development environment which doesn't have SSL configured.

After much head scratching and searching - I still don't fully understand why this happens. The generated HTML refers to the file with a relative path, so logic would dictate that the file should be downloaded using the same method as the page from which it's referenced (namely HTTPS). If anyone can shed any light on this for me - please let me know!