View Full Version : Protecting Sensitive Files
morny
04-07-2005, 01:51 AM
Do you know of a way to prevent users directly accessing files by typing in
their url path.
For example i have a site, where a user must enter the correct username and
password to enter the site. Within this site the user can click on a link
that will launch a pdf file. (unfortunately i have to use pdf files)
However if someone guessed the right path eg
www.mycompany.com/hidden/mypdfile.pdf then they could open the file
without having to log on.
Ive taught of storing the files locally but this wouldnt work as i need to
access the files both at the office, at home and on the move.
Is this possible or do you know of any solutions
For example, people who sell ebooks and such must have a way of protecting unathorised access to the files
Thanks
Paul
glenngv
04-07-2005, 02:33 AM
The link to the file should be something like this:
www.mycompany.com/docs/file.asp?id=123
Then file.asp should check if the user is logged in or not. If not logged in, redirect to the login page. Otherwise, determine which document refers to the specified id. The files should not be located in the web root (wwwroot by default) so that they are not accessible on the web. Access the corresponding file through the ADO Stream object and send it to browser for display. Use this Binary file streaming script (http://marcustucker.com/blogold/200404archive001.asp) for this.
morny
04-07-2005, 02:45 AM
Hello glenngv,
That sounds very interesting but im not very experienced in this sort of thing. Is there any way you could explain it as if you were talking to a dummy.
Here is some information that you may need to help to explain better:
1) All the files will be stored here www.mycompany.com/pdf/
2) The only page someone should be able to access it from is this page: www.mycompany.com/search.asp
and this is the current link that would be used
<a href="private.html" target="_blank" onclick="window.open('<%=rsSearch.Fields.Item("doclocation").Value%>', 'window_name','yes'); return false;">[Click Here To Open]</a>
The <%=rsSearch.Fields.Item("doclocation").Value%> is serverside script and would display the document location eg www.mycompany.com/pdf/myFile.pdf
Any clarification would be a great help and i really appreciate your time
Thanks
Paul
glenngv
04-07-2005, 03:36 AM
Is it ok for you to change the location of the pdf files and structure of your database?
As I said, the field location should not be accessible on the web so the "doclocation" field must not contain an HTTP URL. The following changes are needed:
- the "doclocation" column must contain the local directory of the file (e.g. "c:\pdf\").
- add "docfilename" column that denotes the file (e.g. "myfile.pdf")
- add "docfileid" column that identifies it as "myfile.pdf" (e.g. 123)
If it's possible to do these changes in your database, then we can go on with the full solution.
morny
04-07-2005, 03:41 AM
Yes i can change the location of the files to outside the root. I actually do this with my database.
I can also add the field for holding the docName
Lastly i use msAccess which uses autonumber to give each record a unique id. Would this suffice?
Thanks so much for helping me out
Cheers
Paul
morny
04-07-2005, 03:43 AM
p.s i will change the field names in the database to the exact names you suggested doclocation, docfilename and docfileid
glenngv
04-07-2005, 06:58 AM
search.asp:
<a href="private.html" target="_blank" onclick="window.open('doc.asp?fid=<%=rsSearch.Fields.Item("docfileid").Value%>', 'window_name','resizable=1, width=880, heigh=600'); return false;">[Click Here To Open]</a>
doc.asp:
<%
response.buffer = true
'validate if user is logged in (depends on how you implement your authentication mechanism)
'if not logged in, redirect to login page.
dim fid, fullpath, fso
fid = request.querystring("fid")
'validate file id
if fid="" then
response.write "No document to open."
response.end
elseif not isNumeric(fid) then
response.write "Invalid request."
response.end
end if
'query the db using the file id
sql = "SELECT [docfilename], [doclocation] FROM TableNameHere WHERE [docfileid]=" & fid
'execute query (you already know how to do it)
'check if a document is retrieved
if not rsDoc.BOF and not rsDoc.EOF then
'get full path of the file
fullpath = rsDoc.Fields.Item("doclocation") & "\" & rsDoc.Fields.Item("docfilename")
'check if file really exists
set fso = CreateObject("Scripting.FileSystemObject")
if not fso.FileExists(fullpath) then
response.write "Document not found."
set fso = nothing
'close and kill recordset and connection objects
response.end
end if
set fso = nothing
else
'close and kill recordset and connection objects
response.write "Document not found."
response.end
end if
'write the content of the file to the browser by using the script I linked you to (http://marcustucker.com/blogold/200404archive001.asp)
SendStreamToBrowser(LoadStream(fullpath), rsDoc.Fields.Item("docfilename"), "", true)
'close and kill recordset and connection objects
%>
esthera
04-07-2005, 09:56 AM
hi i just read through this and i'm curious --- does this also work with pdf's and docs. what about a jpg?
glenngv
04-07-2005, 10:28 AM
Yes. Just follow the link I posted earlier to see the binary file streaming script.
morny
04-08-2005, 01:49 AM
Glenngv,
That was great that you took time out to help me. Its people like you that keep these forums going. Anyway ive tried my best to get the code going but because im not very familiar with VBscript im not very good at troubleshooting. I actually use serverside javascript instead of VBScript myself.
Anyway im getting the following error when i try and run the script:
Microsoft VBScript compilation error '800a03f6'
Expected 'End'
/paul/doc.asp, line 236
I have put the following pointer in the code to point out line 236
--------->This is line 236
Here is my full code for the file doc.asp
<%
Response.Buffer = true
'This is my Login Authentication Mode. It redirects if the user is not logged in.
Dim fid, fullpath, fso
fid = Request.Querystring("fid")
' validate file id
if fid="" then
Response.Write "No document to open."
Response.End
else if not isNumeric(fid) then
Response.Write "Invalid request."
Response.End
end if
' query the db using the file id
Set OBJdbConnection = CreateObject("ADODB.Connection")
OBJdbConnection.Open("provider=Microsoft.Jet.OLEDB.4.0; data source=c:\\home\\mycompany\\db\\myDatabase.mdb")
SQL = "SELECT [docfilename], [doclocation] FROM rnd WHERE [docfileid]=" & fid
' execute query (you already know how to do it)
Set rsDoc = OBJdbConnection.Execute(SQL)
'check if a document is retrieved
if not rsDoc.BOF and not rsDoc.EOF then
'get full path of the file
fullpath = rsDoc.Fields.Item("doclocation") & "\" & rsDoc.Fields.Item("docfilename")
'check if file really exists
Set fso = CreateObject("Scripting.FileSystemObject")
if not fso.FileExists(fullpath) then
Response.Write "Document not found."
Set fso = Nothing
' close and kill recordset and connection objects
OBJdbConnection.Close
rsDoc.Close
response.end
end if
set fso = Nothing
else
'close and kill recordset and connection objects
OBJdbConnection.Close
rsDoc.Close
Response.Write "Document not found."
Response.End
end if
'write the content of the file to the browser by using the script I linked you to (http://marcustucker.com/blogold/200404archive001.asp)
'Load a file from disk
Function LoadStream(FilePath)
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1 'adTypeBinary=1
objStream.Open
objStream.LoadFromFile FilePath
LoadStream = objStream.Read
objStream.Close
Set objStream = Nothing
End Function
'returns the MIME header type for a given extension
Function GetMIMEType(Extension)
dim Ext
Ext = UCase(Extension)
select case Ext
'Common documents
case "TXT", "TEXT", "JS", "VBS", "ASP", "CGI", "PL", "NFO", "ME", "DTD"
sMIME = "text/plain"
case "HTM", "HTML", "HTA", "HTX", "MHT"
sMIME = "text/html"
case "CSV"
sMIME = "text/comma-separated-values"
case "JS"
sMIME = "text/javascript"
case "CSS"
sMIME = "text/css"
case "PDF"
sMIME = "application/pdf"
case "RTF"
sMIME = "application/rtf"
case "XML", "XSL", "XSLT"
sMIME = "text/xml"
case "WPD"
sMIME = "application/wordperfect"
case "WRI"
sMIME = "application/mswrite"
case "XLS", "XLS3", "XLS4", "XLS5", "XLW"
sMIME = "application/msexcel"
case "DOC"
sMIME = "application/msword"
case "PPT","PPS"
sMIME = "application/mspowerpoint"
'WAP/WML files
case "WML"
sMIME = "text/vnd.wap.wml"
case "WMLS"
sMIME = "text/vnd.wap.wmlscript"
case "WBMP"
sMIME = "image/vnd.wap.wbmp"
case "WMLC"
sMIME = "application/vnd.wap.wmlc"
case "WMLSC"
sMIME = "application/vnd.wap.wmlscriptc"
'Images
case "GIF"
sMIME = "image/gif"
case "JPG", "JPE", "JPEG"
sMIME = "image/jpeg"
case "PNG"
sMIME = "image/png"
case "BMP"
sMIME = "image/bmp"
case "TIF","TIFF"
sMIME = "image/tiff"
case "AI","EPS","PS"
sMIME = "application/postscript"
'Sound files
case "AU","SND"
sMIME = "audio/basic"
case "WAV"
sMIME = "audio/wav"
case "RA","RM","RAM"
sMIME = "audio/x-pn-realaudio"
case "MID","MIDI"
sMIME = "audio/x-midi"
case "MP3"
sMIME = "audio/mp3"
case "M3U"
sMIME = "audio/m3u"
'Video/Multimedia files
case "ASF"
sMIME = "video/x-ms-asf"
case "AVI"
sMIME = "video/avi"
case "MPG","MPEG"
sMIME = "video/mpeg"
case "QT","MOV","QTVR"
sMIME = "video/quicktime"
case "SWA"
sMIME = "application/x-director"
case "SWF"
sMIME = "application/x-shockwave-flash"
'Compressed/archives
case "ZIP"
sMIME = "application/x-zip-compressed"
case "GZ"
sMIME = "application/x-gzip"
case "RAR"
sMIME = "application/x-rar-compressed"
'Miscellaneous
case "COM","EXE","DLL","OCX"
sMIME = "application/octet-stream"
'Unknown (send as binary stream)
case else
sMIME = "application/octet-stream"
end select
GetMimeType = sMIME
End Function
'Sends the specified file to the browser
sub SendStreamToBrowser(FileStream, FileName, ContentType, IsInline)
Dim FileExt, FileSize
'Disable error checking
on error resume next
'Clear buffer
Response.Clear
FileExt = mid(FileExt, instrrev(FileName,".") + 1)
FileSize = Ubound(FileStream) + 1
'Add filename to header
Response.AddHeader "Connection", "keep-alive"
Response.AddHeader "Content-Length", FileSize
'Check if data should be delivered inline or not
If IsInline = True then
'Allow the browser to render the file inside a browser window (if it can)
Response.AddHeader "Content-Disposition","inline; filename=" & FileName
Else
'Force browser to save file
Response.AddHeader "Content-Disposition","attachment; filename=""" & FileName & """"
End If
'Get ContentType for download
select case ContentType
case false
'Generic binary ContentType and Charset
Response.ContentType = "application/octet-stream"
Response.Charset = "UTF-8"
case ""
'Find out what it should be
Response.ContentType = GetMIMEType(FileExt)
case else
'Use the ContentType that was passed
Response.ContentType = ContentType
end select
'Send data to client
Response.BinaryWrite(FileStream)
Response.Flush
End Sub
SendStreamToBrowser LoadStream(fullpath), rsDoc.Fields.Item("docfilename"), "", true
OBJdbConnection.Close
rsDoc.Close
--------->This is line 236: 'close and kill recordset and connection objects
%>
I hope you can help me Glenn
glenngv
04-08-2005, 02:58 AM
*sigh* It took a while for me to spot the error. The error was you put a space in elseif statement causing an unmatch end if.
' validate file id
if fid="" then
Response.Write "No document to open."
Response.End
else if not isNumeric(fid) then
Response.Write "Invalid request."
Response.End
end if
The confusing error line number made it very hard to debug. :mad:
Here's the modified code. I improved it a bit.
<%
Response.Buffer = true
'Binary file streaming script (You can put it in a include file for code re-use and easy maintenance)
'Load a file from disk
Function LoadStream(FilePath)
Dim objStream
Set objStream = Server.CreateObject("ADODB.Stream")
objStream.Type = 1 'adTypeBinary=1
objStream.Open
objStream.LoadFromFile FilePath
LoadStream = objStream.Read
objStream.Close
Set objStream = Nothing
End Function
'returns the MIME header type for a given extension
Function GetMIMEType(Extension)
dim Ext
Ext = UCase(Extension)
select case Ext
'Common documents
case "TXT", "TEXT", "JS", "VBS", "ASP", "CGI", "PL", "NFO", "ME", "DTD"
sMIME = "text/plain"
case "HTM", "HTML", "HTA", "HTX", "MHT"
sMIME = "text/html"
case "CSV"
sMIME = "text/comma-separated-values"
case "JS"
sMIME = "text/javascript"
case "CSS"
sMIME = "text/css"
case "PDF"
sMIME = "application/pdf"
case "RTF"
sMIME = "application/rtf"
case "XML", "XSL", "XSLT"
sMIME = "text/xml"
case "WPD"
sMIME = "application/wordperfect"
case "WRI"
sMIME = "application/mswrite"
case "XLS", "XLS3", "XLS4", "XLS5", "XLW"
sMIME = "application/msexcel"
case "DOC"
sMIME = "application/msword"
case "PPT","PPS"
sMIME = "application/mspowerpoint"
'WAP/WML files
case "WML"
sMIME = "text/vnd.wap.wml"
case "WMLS"
sMIME = "text/vnd.wap.wmlscript"
case "WBMP"
sMIME = "image/vnd.wap.wbmp"
case "WMLC"
sMIME = "application/vnd.wap.wmlc"
case "WMLSC"
sMIME = "application/vnd.wap.wmlscriptc"
'Images
case "GIF"
sMIME = "image/gif"
case "JPG", "JPE", "JPEG"
sMIME = "image/jpeg"
case "PNG"
sMIME = "image/png"
case "BMP"
sMIME = "image/bmp"
case "TIF","TIFF"
sMIME = "image/tiff"
case "AI","EPS","PS"
sMIME = "application/postscript"
'Sound files
case "AU","SND"
sMIME = "audio/basic"
case "WAV"
sMIME = "audio/wav"
case "RA","RM","RAM"
sMIME = "audio/x-pn-realaudio"
case "MID","MIDI"
sMIME = "audio/x-midi"
case "MP3"
sMIME = "audio/mp3"
case "M3U"
sMIME = "audio/m3u"
'Video/Multimedia files
case "ASF"
sMIME = "video/x-ms-asf"
case "AVI"
sMIME = "video/avi"
case "MPG","MPEG"
sMIME = "video/mpeg"
case "QT","MOV","QTVR"
sMIME = "video/quicktime"
case "SWA"
sMIME = "application/x-director"
case "SWF"
sMIME = "application/x-shockwave-flash"
'Compressed/archives
case "ZIP"
sMIME = "application/x-zip-compressed"
case "GZ"
sMIME = "application/x-gzip"
case "RAR"
sMIME = "application/x-rar-compressed"
'Miscellaneous
case "COM","EXE","DLL","OCX"
sMIME = "application/octet-stream"
'Unknown (send as binary stream)
case else
sMIME = "application/octet-stream"
end select
GetMimeType = sMIME
End Function
'Sends the specified file to the browser
sub SendStreamToBrowser(FileStream, FileName, ContentType, IsInline)
Dim FileExt, FileSize
'Disable error checking
on error resume next
'Clear buffer
Response.Clear
FileExt = mid(FileExt, instrrev(FileName,".") + 1)
FileSize = Ubound(FileStream) + 1
'Add filename to header
Response.AddHeader "Connection", "keep-alive"
Response.AddHeader "Content-Length", FileSize
'Check if data should be delivered inline or not
If IsInline = True then
'Allow the browser to render the file inside a browser window (if it can)
Response.AddHeader "Content-Disposition","inline; filename=" & FileName
Else
'Force browser to save file
Response.AddHeader "Content-Disposition","attachment; filename=""" & FileName & """"
End If
'Get ContentType for download
select case ContentType
case false
'Generic binary ContentType and Charset
Response.ContentType = "application/octet-stream"
Response.Charset = "UTF-8"
case ""
'Find out what it should be
Response.ContentType = GetMIMEType(FileExt)
case else
'Use the ContentType that was passed
Response.ContentType = ContentType
end select
'Send data to client
Response.BinaryWrite(FileStream)
Response.Flush
End Sub
'This is my Login Authentication Mode. It redirects if the user is not logged in.
Dim fid, fullpath, fso, OBJdbConnection, SQL, rsDoc, isFound
fid = trim(Request.Querystring("fid"))
' validate file id
if fid="" then
Response.Write "No document to open."
Response.End
elseif not isNumeric(fid) then
Response.Write "Invalid request."
Response.End
end if
' query the db using the file id
Set OBJdbConnection = CreateObject("ADODB.Connection")
OBJdbConnection.Open("provider=Microsoft.Jet.OLEDB.4.0; data source=c:\\home\\mycompany\\db\\myDatabase.mdb")
SQL = "SELECT [docfilename], [doclocation] FROM rnd WHERE [docfileid]=" & fid
' execute query (you already know how to do it)
Set rsDoc = OBJdbConnection.Execute(SQL)
'check if a document is retrieved
isFound = false
if not rsDoc.BOF and not rsDoc.EOF then
'get full path of the file
fullpath = rsDoc.Fields.Item("doclocation") & "\" & rsDoc.Fields.Item("docfilename")
'check if file really exists
Set fso = CreateObject("Scripting.FileSystemObject")
isFound = fso.FileExists(fullpath)
set fso = Nothing
end if
if not isFound then
Response.Write "Document not found."
else
SendStreamToBrowser LoadStream(fullpath), rsDoc.Fields.Item("docfilename"), "", true
end if
'close and kill recordset and connection objects
OBJdbConnection.Close
rsDoc.Close
Set OBJdbConnection = nothing
Set rsDoc = nothing
%>
morny
04-08-2005, 04:17 AM
Please see private message Glenn
Thanks
Paul
glenngv
04-08-2005, 04:44 AM
I tried it with IE6 and Firefox 1.0.2 and both worked. I was able to open the pdf and png files successfully. Although in Firefox, the pdf and png files are opened in its associated application and not in the browser window itself. But normally in other sites that have normal links to those type of files, the file is opened in the browser itself.
If it matters, my acrobat version is 5.
morny
04-08-2005, 05:42 AM
Glenn Youre right. Ive tried it in Firefox and Netscape and it works fine. Both dont auto launch in borwser but this is no big deal. The only thing i noticed that would cause a problem is on firefox for the .png file periodically i get a browser page opened up with just this in the top of the page and the rest of the page is just white:
2>, line 224</font>
Thats it absolutely nothing else on the page.
Just as i was writing this i noticed it only happens if i open the pdf file first and then close the pdf file and then open the .png file. This is a weird error, check it out yourself. If i dont open the pdf file there is no error, well its not really an error its as if its writing a small peice of code.
The reason im having the problem with Internet Explorer is i still have I.E 5.0 because when i uploaded to I.E the last time my pc couldnt access the internet and the only way i could get it to work was to wipe hard drive and re-install, even tech support from Dell or my ISP could not solve it, it probably was nothing to do with I.E 6 but i got paranoid and installed an older version.
I have firefox 1.0, are you using the same one, i might try updating there seems to be a 1.0.2 available now.
Thanks
Paul
glenngv
04-08-2005, 06:36 AM
That seems to be a vbscript runtime error message. Did you view the source? The complete error message might be in the page source.
Just as i was writing this i noticed it only happens if i open the pdf file first and then close the pdf file and then open the .png file. This is a weird error, check it out yourself. If i dont open the pdf file there is no error, well its not really an error its as if its writing a small peice of code.
I tried what you said and I saw no error in my FF 1.0.2, both types of files were properly displayed.
morny
04-09-2005, 03:23 PM
Glenn,
There dosent seem to be any error in the source code. Just looks like an encrypted file or like the gobbledy gook you see if you try to open a graphic file in notepad.
With that in mind it might be possible that the wrong program is trying to open the wrong file. i.e the browser is trying to display the png file in pdf format and vice versa. The reason i say this is it only happens if i do one of the following:
1) Open up the png file and then try to open the pdf file.
2) Open the pdf file and then try to open the png file.
If i try to open the png file 30 times in a row it works fine. And if i try to open the pdf file 30 times in a row it works fine. So maybe its not running the part in the script where it checks what program file it is eg pdf,png,fla,doc etc the second time round for some reason?
Just my taughts im probably a million miles away. I tried pasting the whole code but it wont seem to let me. Theres pages and pages of it but i think its blocking it because of the special characters. Heres as much as it will let me display, this is the source after i try and open the pdf file directly after opening the png file:
%PDF-1.2
%
12 0 obj
<<
/Length 13 0 R
/Filter /FlateDecode
>>
stream
H‰•Tn0A4|&vc ƒ]ˆ…N›)‰RT "–—}f
5Š
G—#;?’lbQ)•‹\Hƒ’3
R.žŠŸzy:dSTcy&tOd#
glenngv
04-11-2005, 02:49 AM
Does this happen in your Firefox? I tried it in mine (FF 1.0.2) and it worked. I was able to open pdf and png files alternately. A blank window is opened and the Open/Save dialog box is invoked and if I choose Open, the file is opened file in its associated application. Maybe the problem in your side is with the pdf plugin or the FF version?
morny
04-11-2005, 02:58 AM
Glenn,
Yes, I tested it in Firefox 1.0. I was just pointing out that older versions had problems. As there will be a limited number of people using this it would be fine. However this would not be suitable to a wider audience as not everyone has their browsers up to date and they would think there was an error with the coding.
Nonetheless it was a smashing job by you, and i really appreciated everything very much. I dont think i would have come up with a solution if i had spent a month reading and testing. Your a credit to the forum.
Again, just pointing out if anyones trying to use this code that the above code only works in Firefox 1.0.2 or above and Internet Explorer 6 or above (pdf files wont open in Explorer 5) i have tested it in netscape aswell and it works a treat in version 7.2 but i havent tried it on an older netscape version.
Thanks Glenn
Paul
glenngv
04-11-2005, 03:35 AM
Glad to be of help. :)
You should also thank Marcus Tucker for the binary streaming script which is the main script of your page. He is m@rco (http://www.codingforums.com/member.php?u=9839) here in CF.
vBulletin® v3.8.2, Copyright ©2000-2010, Jelsoft Enterprises Ltd.