I'm working on a website where I need to prevent the direct linking to a few pdf files. I'm using ASP.net 2.0. Is there an easy way in code to do this? or some simple IIS setting?
Right now i'm just using a standard anchor tag to link to the files. i can validate the user on the page containing the anchor tag but that still doesn't stop the user from nabbing the url and passing it on to someone else.
I've solved this in the past by using a file-fetcher asp page and streaming the bytes of the desired file, using the correct content-type in the header. Roughly:
Create page fetchfile.aspx
Sample URL: yoursite/fetchfile.aspx?n=pdfname.pdf
In fetchfile:
- Verify user is permitted to access file.
- Check chosen directory for presence of file from query string.
- Set content-type appropriately for file type.
- Open the file and stream all bytes of it to the client.
- Close the file and end the response.
Do not send anything in the response except the bytes of the file. If an error occurs, either redirect or return error html with the content-type set correctly.
The last time I did this I was serving up images, so I found a suitable free library and wrote my error message into a new custom image that could then display. For fun, you can use this technique to serve up content that is unexpected when anyone steals your bandwidth by hot-linking like this:
Create a blacklist with unwanted referrer names, in a database table or text file.
When a request for a file comes in, if the user is not allowed, check if the referrer is in the blacklist, and if not, let the file be read.
On a regular basis, check the referring pages and decide a suitable pdf to return to punish that site.
Add the content you want to return to your blacklist for each referrer, and when the referrer IS in the blacklist, then return the alternate diddled content.
This is a great way to make people REALLY unlikely to steal your stuff. Their experience looks like this:
They find some nice content they want to "borrow."
They post it on their site and it works just fine.
The next day you see their action and add them to the blacklist table but make it so anyone trying to obtain the content instead gets a nice little message of some sort: "example.com is STEALING this content from the owners at somecoolsite.com. Please let them know that you are displeased with their actions."
You have a good laugh.
This can be especially wonderful if the content being stolen is an image. Embarrassments galore are in store for bandwidth thieves!
Some extra clever IP-address and time comparison could possibly make you show the correct content to the actual perpetrator but the wrong content to any of his site visitors... evil and delicious.
Create an HttpHandler to process all requests for .pdf. Since ASP.Net doesn't process PDF files out of the box, the HttpHandler will intervene and the web.config tell IIS to do so.
The Code
namespace YourNameSpace
{
public class HttpHandlerClassName: IHttpHandler
{
public bool IsReusable
{
//We dont want this class to be reused simply
//because we dont want other requests to wait and lie pending
//suggests that an instance of this class cannot
//be reused to serve more than one request.
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
string MyReferrer = context.Request.UrlReferrer.ToString();
//do some regex to determine if the request is originating from
//your site.
//Put logic for the behavior your want for the outcome of your
//RegEx match here
}
}
}
web.config
<system.web>
<httpHandlers>
<add verb="*" path="*.pdf" type="YourNameSpace.HttpHandlerClassName,YourAssemblyName"/>
</httpHandlers>
</system.web>
Place the files in your App_Data folder and serve them using an HttpHandler. Inside the handler you can check the Session.IsNewSession property to see if the request is coming from outside your website. But you'd probably want to include some kind of authentication and validation inside the handler as well.
Put the PDF files in a directory. Use .htaccess and or robots.text.