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.
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!