Link to home
Start Free TrialLog in
Avatar of GeorgeJacobson
GeorgeJacobsonFlag for Canada

asked on

Restrict access to PDF files on a password secured website

IIS sub directory - how to allow autorized users access only for users users that have logged on to a website

Restricting access of a .pdf document (e.g. 'Reader.pdf') to internal caller only.
Website IP address is 64.225.112.40. The test directory to use is '/p1search'.

In IIS, under "Security" Tab  of "Property" of a particular directory (e.g. '/p1search'), the top part of the dialog box is "Enable anonymous access" - If checked, one specifies an account, whose default is 'ISER_WINDOWS2003' (Internal Guest Account). The others are 'IWAM_WINDOWS2003' (Launch IIS Process Account), 'Administrators', 'ASP NET', 'VUSER_WINDOWS2003' (?), etc. If not check, it doesn't ask for an accout.
The bootom part of this dialog box are four checkboxes: 'Integrated Window authentication','Digest authentication for Windows domain servers','Basic authentication (password is sent in clear text)', and '.NET Password authentication'.

The objective is to configure, using this security dialog box, is to restrict the access to a particular directory ('/p1search') from any callers that originates from within the same website (e.g. 64.225.112.40) alone, i.e. any URL of the form "<directory><filename>" is accessable; whereas, any URL of the form "http://<website><directory><filename>" (e.g. 'http://64.225.112.40/p1search/Reader.pdf') has access to be denied. When I set anonymus account to be 'ON' using IUSR_WINDOWS2003, the this particular directory is accessable, including going through URL of the form "http://<website><directory><filename>" (this URL is entered at Address text box of an Internet Explorer (or of FireFox's one); evenmore, Google crawler can access this directory. But I desired to disable such access. Only place to access this directory ('/p1search') is to be called from .asp program's <a href="<directory><filename>" (e.g. '../p1search/Reader.pdf'), where this caller asp program resides at same server as this particular directory ('/p1search'), and at same website address ('64.225.112.40').

If it is not with 'Security' dialog box, Right-clicking on a particular directory (e.g. '/p1search'), then submenu item 'Permission' may be so. In there, there are various system accounts (IUSR_WINDOWS, IWAM_WINDOWS, Administrators, ASP Net, etc..), having capable of setting permission parameters. The problem is WHICH account is Set to be 'enabled'; whereas, which one should set to be 'denied'.
Avatar of chisholmd
chisholmd

OK I am trying to follow what you are asking so I'll try to break it out one at a time.

If you want remove anonymous access just uncheck "allow anonymous access" and also using windows explorer go to that directory, right click, choose properties security and remove the "iusr_..." account.

Now for only allowing access from the same web site I think what you are looking for is referrer.  The location of the client is always the IP address of their computer.

you can use the servervariables collection to access where the client is being refered from.

So for example:

if instr(Request.ServerVariables("HTTP_REFERER"),"your-domain.com")  then
  'allow them access
else
  'access denied redirect them somewhere else.
end if

If you want to allow Google in, I know you said you didn't, but if you did you could do something like:

if instr(Request.ServerVariables("HTTP_REFERER"),"your-domain.com")  OR instr(Request.ServerVariables("HTTP_USER_AGENT"),"googlebot") then

So,  if your goal "is to restrict the access to a particular directory ('/p1search') from any callers that originates from within the same website"   You can simply use the referrer check and ignore the other security settings.

Just be aware that while this will keep out 99% of the people a motivated and knowledgeable person could spoof the referrer.  So don't use this method to secure things like customer credit cards :)


Avatar of GeorgeJacobson

ASKER

Thx (sorry for the confusing question layout),

Basically I am trying to restrict access to PDF files on a password secured website http://64.225.112.40/p1search/Reader.pdf.  ( I can provide you a test ID/PW for http://64.225.112.40 if this helps)
Currently the p1search directly is checked on for "allow annonymous access", so anyone can access the pdf file.  I wish to restrict it only to authorized web-site users ie those that have logged on to the site http://64.225.112.40.  
Given that it is a pdf file, I don't know how I can embed the referrer check.  I did find a PHP solution but do not know how to implent this in ASP or HTML.
(https://www.experts-exchange.com/questions/21159208/secure-pdf.html?query=restrict+pdf+file+access&clearTAFilter=true).

More often, The referrer to .pdf file is accessed by executing <a href="/p1search/Reader.pdf"> HTML tag. This <a href - - - > tag can be found in pure HTML source code (a client-side code). What I would want to do is that: if source HTML code resides in same web site address (e.g. 64.225.112.40), document 'Reader.pdf' is accessable; hoverver, if one access from outside (including typing http;// URL address in Internet Explorer or Firefox (or even by Google crawler), access to 'Reader.pdf' and content of entire directory '/p1search' should be denied.

Using if-then-endif construct in ASP code would not work because it is server-side processing. This ASP contruct uses '' if instr(Request.ServerVariables("HTTP_REFERER"),"your-domain.com") then  'allow access  ''. Use of embedding .pdf file in ASP code also would not work because one can by-pass that ASP code: instead, one can access to this .pdf directly.

As for Google, I am ok with the Google crawler indexing the pdf file, as long as no-one can access it.

THX alot!
cheers!
Geo
One way to do it would be to use SERVERXMLHTTP object with authentication. Its a bit convoluted so let me just outline the solution.  

1) create a secure directory for your PDF and a special account to acces it lets call it  'pdfaccount'

2) Create an ASP page that does the referer check. If they are accessing from your website then
    Use SERVERXMLHTTP object with authentication to fetch the PDF from the secure directory and then stream it out to the client.

This way the only way to access the PDF is via your script that passes the 'pdfaccount' credentials, direct access would fail.

Here is an example of passing login information from SERVERXMLHTTP (the example is in jscript but you can convert to vbscript easily enough.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/95146cd5-aee8-4131-8ba6-10fa0af91ce7.asp

<%@language=Jscript%>
<%
   var objSrvHTTP;
   objSrvHTTP = Server.CreateObject("Msxml2.ServerXMLHTTP.3.0");
   objSrvHTTP.open ("GET","http://someotherserver/secure.asp",false, _
                       "testuser", "testpassword";
   objSrvHTTP.send ();
   Response.ContentType = "text/xml";
   Response.Write (objSrvHTTP.responseXML.xml);
%>

Also, this example looks incomplete to me, I remember having to do two requests, but maybe that was accessing HTTPS...


Regarding step #1, how do I create a special account to be called 'pdfaccount ? I cannot simply enter any arbitrary name by clicking on 'Add' button of 'Security' tab of a directory's property. When I do, I get error message: "Cannot find 'pdfaccount'" because 'pdfaccount is not on the list. Exactly what do I mean by special account 'pdfaccount', and how Do I establish such account ?

Thank-you very much.
What I mean is a windows user account. IUSR_ is just a special windows account used for anonymous access. What you want is a directory that IUSR_ does not have access to. So go to computer management create a windows account, name it whatever you want.

Then create a directory and assign this account read permissions and make sure IUSR does NOT have read permissions.

OK, so now on your website create a script that checks that they are being refered by your site and if they are you can use the SERVERXMLHTTP obejct to select the PDF from teh secured directory. Since that directory does not allow access by IUSR_ you will add the username you created to the SERVERXMLHTTP obejct to make an authenticated request.

The overall point of this method is that ISUR_ is running a script that will use a different account to access the PDF via the SERVERXMLHTTP object.  So only the script has access to the file and the user can not deep link to it.  

This is kinda an advanced technique as you will probably run into problems figureing out how to use SERVERXMLHTTP to fetch and restream the binary out to the client.

You'll have to decide how important it is and if it is worth the effort. I don't know of any easier method.
Sorry, have been away.
I have set up the Windows user account and will try your recommendation later today and will let you know.
THX!
cheers,
Geo
In IIs, I unchecked "Anonymous Access" for directory '/p1search' in its Security settings.
In Windows Explorer, I right-click on directory '/p1search', choose Properites, then Security tab,
and removed 'IUSR_' account so that there is no anonymous access.

In ASP code, I have added object "Msxml2.ServerXMLHTTP.6.0".
To use this object, I have downloaded "msxml6" (MSXML Parser 6.0) from www.microsoft.com.
The ASP vbscript is as follows:

    Dim objSrvHTTP
    Set objSrvHTTP = Server.CreateObject("Msxml2.ServerXMLHTTP.6.0")
    objSrvHTTP.open "GET", "http://64.225.112.40/p1search/Reader.pdf", False, "<account>", "<password>"
    objSrvHTTP.send()
    Response.ContentType="text/xml"
    Response.Write objSrvHTTP.responseXML.xml

Followed by, in HTML, statment

    <a href="p1search/Reader.pdf"><u>Test PDF forms</u></a>

I notice that, in statement "objSrvHTTP.open "GET", ...", URL must contain web-side address; otherwise I get an error.
I have tested on my localhost. There, this statement will then be read:      

   objSrvHTTP.open "GET", "http://localhost/p1search/Reader.pdf", False, "<my localhost account>", "<its password>"

But I still dont get my results !!

Instead, the screen ouput is produced as the folowing:

- <html>
  - <head>
      <title>Test PDF</title>
    </head>
  - <body leftmargin="0" rightmargin="0" topmargin="0" bottommargin="0">
    - <a href="p1search/Reader.pdf">
        <u>Test PDF forms</u>
      </a>
    </body>
  </html>

Even if when its corresponding source code generated is as follows:

<html>
<head>
<title>Test PDF</title>
</head>
<body leftmargin="0" rightmargin="0" topmargin="0" bottommargin="0">
      <a href="p1search/Reader.pdf"><u>Test PDF forms</u></a>
</body>
</html>


It is like an expanding XML tree structure. I clicked on <a href  > statement, nothing happens!  No pdf viewing.

However, If I removed last two statements "Response.ContentType="text/xml" and Response.Write objSrvHTTP.responseXML.xm",
Then It goes ordinarily to next HTML page, containing a hyperlink to "Reader.pdf" document file.
Unfortunately, whether it can be access or not is still not working: when I have denied IUSR_ account but grant only
to specific account "<my localhost account>" and "<its password>", I get "Enter network password" dialog box; if "cancel",
I get "You are not authorised to view this page" message. (If I entered with an authorized account, e.g. Administrator,
I have accessed "Reader.pdf"; but this method of entering authorized Username/Password becomes too cumbersome
for most ordinary member users; and therefore, there must be a way to automatically process with such authorized Username/Password.)

On the other hand, If I grant an anonymous access in Security, I am able to access "Reader.pdf" BUT unfortunately,
at the cost that "Reader.pdf" can be accessed directly by anyone!

I beleave that I don't know how to use XML coding becuase I treat them like an HTML code.
I would like to know how to program in ASP that contains a reference (via '<a href   >')
to 'Reader.pdf' in ASP page, apart from using ServerXMLHTTP object.
There should be no other HTML nor anything else written out to the clients browser.

Your page should look sort of like this:
<%
'if locally referered then
   objSrvHTTP.open "GET", "http://64.225.112.40/p1search/Reader.pdf", False, "<account>",  "<password>"
   objSrvHTTP.send()
   Response.ContentType= "whatever the mime type for PDF is"
  Response.BinaryWrite objSrvHTTP.responseBody
'else
'end if
%>


Tell you what I have read a few questions like this so I'll write up an article for one of my sites with a tutorial and then come back and post the link. Hoipefully today :)





ASKER CERTIFIED SOLUTION
Avatar of chisholmd
chisholmd

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thank you very much.  We have implemnted & tested your solution successfully!

We installed msxml6.msi, in the IIS Directory security, Authenitiacation method, set no Annoynmous access, checked Integrated Windows Authentication. In Windows Explorer for the sub-directory security tab: Deny permission to Every_Body and ISR, then we created an account.  

As you pointed out, once the user has accessed the pdf file, via the ASP page (ie logged in to the web-site), then the account User Name/Password seems to be kept in the cache and can be acccessed directortly from the file path with the pdf extension (but must have already accessed once via a log-in).

THX again:-)
Geo
>User Name/Password seems to be kept in the cache and can be acccessed

I don't think its a cache I think its for the session only. But, I havn't tested that.
Yes - I believe you are correct, upon further testing, we agree - it is the session .  Close down the browser and the file path can not be reached.

Again, THX ALOT for your help (and perseverence), you were absolutley amazing in your help!  Kudoos to you - you really helped us out of a "jam"! :-)

cheers,
Geo