As web developers we are often creating ways for people to upload files. Usually uploading a file is pretty trivial and there are numerous examples of how to do it across the Internet. From time to time we have the need to secure the file we are uploading, to prevent someone from directly navigating to the file and downloading it without our permission. It is at these times that we have to modify the file upload process just a bit in order to prevent direct access to our files. Of course, we still need to be able to use the files that are uploaded, so this walkthrough will show you how to upload and secure your files and also how to download your secured files.
The premise of our security is that files with the file extension of “.resource” are not served by web servers, at least not by IIS. Therefore all we have to do is add the file extension of “.resource” to any file we upload. If we uploaded a file named, “Gnome.jpg”, we would store it on the server as “Gnome.jpg.resource”. If someone were to try to navigate directly to the URL associated with the “Gnome.jpg.resource” they wouldn’t be able to pull up the image.
When we download the file we simply rename the file back to “Gnome.jpg” and start the download. In order for this to make sense you will need a way to secure who has access to download the file. I usually do that based on Roles in Dotnetnuke, but you can do it anyway you want.
THE ASCX OR ASPX CODE
First let’s look at the .ACSX or the .ASPX code (depending on what you are using).
<INPUT id="fuFuncATTACHMENTSFile" type="file" size="20" name="fuFuncATTACHMENTSFile" class="CommandButton" runat="server" style="height: 1.75em; width: 210px;">
<asp:Button id="btnFuncATTACHMENTUpload" runat="server" CssClass="CommandButton" Width="67px" Text="Add File" CausesValidation="False"></asp:Button>
Above is your standard input box used to select file attachments. I would point out that the ASP:Button has the "CausesValidation” property set to FALSE in order to prevent any valuators on the rest of your form from firing during the file selection process.
THE UPLOAD CODE
When the ASP:Button, “btnFuncATTACHMENTUpload” is clicked the following code is fired:
Protected Sub btnFuncATTACHMENTUpload_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFuncATTACHMENTUpload.Click
'Grab the file name from its fully qualified path at client
Dim strFileName As String = fuFuncATTACHMENTSFile.PostedFile.FileName
' only the attched file name not its path
Dim c As String = System.IO.Path.GetFileName(strFileName)
'Save uploaded file to server
'Storing the file name
Dim arrFileName As String()
'Getting just the file name
arrFileName = strFileName.Split(Convert.ToChar("\"))
'Saving the attachment
fuFuncATTACHMENTSFile.PostedFile.SaveAs("c:\inetpub\DNNTest\FileStore\" & strFileName & ".resource") 'adding .resource for securityEnd Sub
THE CODE FOR DOWNLOADING
Protected Sub imgFuncDocumentsView_Click(ByVal sender As System.Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles imgFuncDocumentsView.Click
'replace STOREDFILENAMEwithRESOURCE with the name of the secure file, which would include the .resource extension
'replace ORIGINALFILENAME with the original name of the file or some other name that you want to appear when downloading.
'Calling procedure StreamFile
StreamFile("c:\inetpub\DNntest\FileStore\" & STOREDFILENAMEwithRESOURCE & ".resource",ORIGINALFILENAME)
End Sub
Private Sub StreamFile(ByVal FilePath As String, ByVal DownloadAs As String)
DownloadAs = DownloadAs.Replace(" ", "_")
Dim objFile As New System.IO.FileInfo(FilePath)
Dim objResponse As System.Web.HttpResponse = System.Web.HttpContext.Current.Response
objResponse.ClearContent()
objResponse.ClearHeaders()
objResponse.AppendHeader("Content-Disposition", "attachment; filename=" & DownloadAs)
objResponse.AppendHeader("Content-Length", objFile.Length.ToString())
Dim strContentType As String
Select Case objFile.Extension
Case ".txt" : strContentType = "text/plain"
Case ".htm", ".html" : strContentType = "text/html"
Case ".rtf" : strContentType = "text/richtext"
Case ".jpg", ".jpeg" : strContentType = "image/jpeg"
Case ".gif" : strContentType = "image/gif"
Case ".bmp" : strContentType = "image/bmp"
Case ".mpg", ".mpeg" : strContentType = "video/mpeg"
Case ".avi" : strContentType = "video/avi"
Case ".pdf" : strContentType = "application/pdf"
Case ".doc", ".dot" : strContentType = "application/msword"
Case ".csv", ".xls", ".xlt" : strContentType = "application/vnd.msexcel"
Case Else : strContentType = "application/octet-stream"
End Select
objResponse.ContentType = strContentType
WriteFile(objFile.FullName)
objResponse.Flush()
objResponse.Close()
End Sub
Public Shared Sub WriteFile(ByVal strFileName As String)
Dim objResponse As System.Web.HttpResponse = System.Web.HttpContext.Current.Response
Dim objStream As System.IO.Stream = Nothing
' Buffer to read 10K bytes in chunk:
Dim bytBuffer(10000) As Byte
' Length of the file:
Dim intLength As Integer
' Total bytes to read:
Dim lngDataToRead As Long
Try
' Open the file.
objStream = New System.IO.FileStream(strFileName, System.IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
' Total bytes to read:
lngDataToRead = objStream.Length
objResponse.ContentType = "application/octet-stream"
' Read the bytes.
While lngDataToRead > 0
' Verify that the client is connected.
If objResponse.IsClientConnected Then
' Read the data in buffer
intLength = objStream.Read(bytBuffer, 0, 10000)
' Write the data to the current output stream.
objResponse.OutputStream.Write(bytBuffer, 0, intLength)
' Flush the data to the HTML output.
objResponse.Flush()
ReDim bytBuffer(10000) ' Clear the buffer
lngDataToRead = lngDataToRead - intLength
Else
'prevent infinite loop if user disconnects
lngDataToRead = -1
End If
End While
Catch ex As Exception
' Trap the error, if any.
objResponse.Write("Error : " & ex.Message)
Finally
If IsNothing(objStream) = False Then
' Close the file.
objStream.Close()
End If
End Try
End Sub
NOTE: This code is presented as an example of how you could secure a file. The above example is intended as a good starting point to implementing your own secure file routine. Use at your own risk. Hilbert Solutions, LLC is not responsible for any damage this code example might do. Also note that this examples contains pieces of other examples across the Internet and therefore is not considered to be original in anyway.