Introduction
If you've developed any kind of e-commerce system that offers downloadable files, you've faced this problem. How do I protect my files from theft? Very often, the problem doesn't even concern payment. Many web-sites offer useful files for free. All they ask in return is that the person downloading the file simply enters some personal details, or fills out a form for the administrator's records. All too often, people don't even want to do that and they seek ways to circumvent the web server's security.
The key problem in this scenario is the fact that, no matter which way you look at it, ultimately, you have to offer users a link to the downloadable file. Once someone has that link, they can offer it to their friends and colleagues, who then simply circumvent all of your security features and download the file directly. None of the security features you put in place are worth anything if a user knows that final link to the downloadable file itself. I've seen sites that go to great lengths to "hide" these links (including masking the link by writing specific text in the browser's status bar when a user hovers over it). A simple "View Source" circumvents all these security measures.
The problem lies in the fact that your downloadable file (whether it be a .pdf, .doc, or .zip - or even a .exe) has no way to decide whether it should serve itself or not. You can't place logic in these files to decide whether or not to serve them.
One alternative is to place system security on the folder in which these files reside. This is not really viable though, as you would need to create a new system (Windows) account for each registration, send the person their username & password, and then remove their user account from the system once they have downloaded the file. This makes for an administration nightmare (not to mention an even bigger system security issue). And if you're hosting your site with an external ISP, it's highly unlikely that they'll allow you to create and delete user accounts on their server at will.
The simple solution below closes the above security hole by storing the downloadable file outside a web-site and then serving the file directly from a web page. In other words, you might link to MyFileServer.aspx and receive MyPdfDownload.pdf, for example - with no actual link to MyPdfDownload.pdf offered anywhere on your web-site.
Using the code
The code is fairly straightforward. What we're going to do is open a file stream and serve that instead of the usual text content. In other words, our .aspx page is going to behave more like a file-download. I'm using VB.NET, but this can just as easily be done using C#.
My code below assumes that you've created a folder called C:\My External\File Path\. Note, this folder exists in the C:\ drive and doesn't appear anywhere near C:\Inetpub\wwwroot or any other folder that serves as a web-site on the server. I'm assuming a file called MyPdfDownload.pdf exists in the above folder. You can add any file/ path you choose. Simply update the variables in the appropriate line of code below.
To design the application, first create a folder called C:\My External\File Path\. Then find a .pdf file (you can select any downloadable (.zip, .exe, .doc, .xls etc.) and store it in the above directory. Name it MyPdfDownload.pdf, or change the code below to reflect the file name you've saved in the above folder..
Now check that the directory has appropriate access for the ASP.NET account:
- navigate to c:\My External\.
- right-click on the File Path folder and click on Properties.
- Select the Security tab.
- If you can't see the ASP.NET account, add it.
- Highlight the account and give the user Full Control.
- Click Apply or OK.
Good. Now you have a folder outside the web. Now create a new ASP.NET web application in Visual Studio .NET.
Add a new Web Form and call it MyFileServer.aspx. Double-click on the page. This will open the code-behind (MyFileServer.aspx.vb) file and create your Page_Load
event handler.
We're going to place our code inside this Page_Load()
subroutine. This means that every time users link to our page, it will validate them and decide whether to download our external page or not. Think of this as a delegate function, or an alias for the actual file we want to download. The only difference is that now we can put server-side logic in place to decide whether or not we are prepared to serve the file. In other words, we're wrapping some intelligence around our downloadable file that verifies whether or not it should download itself.
Let's start coding.
Dim fs As FileStream
Dim strContentType As String
Dim strPath = "C:\My External\File Path\"
Dim strFileName As String = "MyPdfDownload.pdf"
If UserIsValid() Then
fs = File.Open(strPath & strFileName, FileMode.Open)
Dim bytBytes(fs.Length) As Byte
fs.Read(bytBytes, 0, fs.Length)
fs.Close()
Response.AddHeader("Content-disposition", _
"attachment; filename=" & strFileName)
Response.ContentType = "application/octet-stream"
Response.BinaryWrite(bytBytes)
Response.End()
Else
Response.Write("Sorry. You don't have access" & _
" to this file. Please return to the login page and try again.")
End If
Points of Interest
XP has some new security settings that may cause problems on the file download feature in browsers. You'll probably need some instructions for people with XP systems to follow. This is a short-term thing - and it's something they'll experience on any file download over the web. As users become accustomed to XP's settings and defaults, they should begin placing fewer support calls.
As a rule, I post the following under the FAQs of any site that uses the above code:
- Q. I can't download documents from the site. When I click the Download button, the screen pops up, then immediately disappears. Why won't the files download?
- A. You're probably using Windows XP, which has default settings that prevent you from downloading documents automatically. The only way around this problem is to disable XP's default browser settings and allow it to automatically download documents:
- In your IE browser, click Tools | Internet Options
- Go to the Security tab, then click the Custom Level button.
- Under the Downloads section of the list, look for Automatic prompting for file downloads and click Enable.
- Click OK.
Sean Young is the lead developer for a company based in Johannesburg, South Africa. His experience includes development of web applications using ASP, Java, and PHP. He also has experience in C++ and has developed several applications in this language, including a fully-fledged mail server.
His more recent projects include a web portal that allows users with no HTML knowledge to design and manage content on their own web sites. The application allows them to simply copy content from any office document, such as MS Word, or Excel and paste it into their web page.
The portal offers many features, including secure secure file download, and a custom form design interface that allows users to design their own forms on the fly. The form information is mailed to a specified recipient each time it is submitted.
Check out the author's Homepage to see this product in action!