A client had been posting training files and some order templates in an unmarked directory on their website. None of them are really all that secret, but some contact lists and other things got picked up by google.
So, they’ve got pages and pages on their intranet that has links to these docs. Templates for new orders, insurance forms, calculators for price lists, etc… So, I can’t just move them. They are a mixture of doc, xls, docx, xlsx, etc… just random crap.
Initially, I figured, I’ll just put in a nice handler to catch things first (which is so easy that it took me all damn day – I’ll get into that later!)
Here was the real problem: The intranet site it is written in classic asp, so the session variables, so my standard “if session(“loggedin”)<>true then goto login page” isn’t going to work. Classic asp doesn’t have the ease of a handler and if there is a way to do it, well…. I really don’t want to know. Seriously, I’m not going to learn how to write something complicated in a dead language. I’d prefer to learn something new that will be useful in the future.
So, sticking with the .Net handler idea. Here’s the theory I decided upon. Yes, I know, it is horrible, but here it is:
All I’m going to do is check to see if the referring page was within the intranet site. Think about it… If you really really really wanted to, you could write a script that would rip out those files, but seriously…. this is about all it really needs and I’m not going to make a new login page.
Here’s how I started:
Imports Microsoft.VisualBasic Imports System Imports System.Web Imports System.Web.UI Imports System.IO Public Class secureDocs : Implements IHttpHandler Dim mimes As New contentTypes Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest Dim f, strReqPath, filePath, sql As String strReqPath = context.Request.Path Dim ref As String = context.Request.ServerVariables("HTTP_REFERER") Dim fileOK As Boolean = False Dim strliveSite As String = ConfigurationManager.AppSettings("public-domain") 'I keep these values in my web.config as appsettings Dim strlocalSite As String = ConfigurationManager.AppSettings("local-domain") Dim liveSite As Integer = InStr(ref, "http://" &amp;amp; strliveSite) Dim localSite As Integer = InStr(ref, "http://" &amp;amp; strlocalSite) If liveSite > 0 Or localSite > 0 Then fileOK = True If Not fileOK Then ' normally, I'd be checking to see if the user was logged in ' and then send them to a login page, but I just don't have ' the budget for that right now. so.... context.Response.Write("THIS IS A SECURE FILE") Exit Sub End If f = context.Request.Path.Substring(context.Request.Path.LastIndexOf("/") + 1) filePath = context.Request.PhysicalPath Dim strContentType As String Dim extension As String = context.Request.Path.Substring(context.Request.Path.LastIndexOf(".") + 1) strContentType = mimes.getContentType(extension) Try Dim file As New FileInfo(filePath) Dim len As Integer = file.Length context.Response.Clear() context.Response.AddHeader("Content-Disposition", "inline; filename=" &amp;amp; file.Name) context.Response.AddHeader("Content-Length", file.Length.ToString()) context.Response.ContentType = strContentType context.Response.WriteFile(file.FullName) Try context.Response.End() Catch ex As Exception End Try Catch ex As Exception context.Response.Write("FILE DOES NOT EXIST") Exit Sub End Try End Sub Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable Get Return False End Get End Property End Class Class contentTypes Dim _types As New StringDictionary Sub New() makeKeys() End Sub Public ReadOnly Property getContentType(myExtension As String) As String Get Return _types.Item(myExtension) End Get End Property Sub makeKeys() _types.Add("acx", "application/internet-property-stream") _types.Add("ai", "application/postscript") _types.Add("aif", "audio/x-aiff") '---- a whole bunch more mime types here -----' _types.Add("z", "application/x-compress") _types.Add("zip", "application/zip") End Sub End Class
Now, that file I stick into my app_code directory and I can then reference it by putting it in my web.config file.
it needs to be in two spots:
<system.web> <httpHandlers> <add verb="*" path="/client_files/*" type="secureDocs" /> <add verb="*" path="/someOtherDirectory/*" type="secureDocs" /> </httpHandlers> </system.web>
And you’re also going to need to tell the server that you don’t care what the file is, but you absolutely MUST kick off aspnet when you are in the
directories where these files are. Otherwise, IIS will see .doc or .xls and just give it to them without hitting your handler.
<system.webServer> <handlers> <add name="sd" path="client_files/*" verb="*" modules="IsapiModule" scriptProcessor="C:\windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" /> </handlers> </system.webServer>
HOWEVER…. If you run a shitty old server that still has IIS 6.0 on it, this latter module doesn’t work.
You need to open IIS on the server, hit the properties for your website, go to “home direc