locked
Restricting static images from downloaders RRS feed

  • Question

  • User1493956762 posted

    I'm using HTTPModule to restrict everything that can download static images, everything is working fine in browsers but when I tried with a downloader it downloaded the image without caring of Response.Write() or Response.OutStream.Write(). Here is the code

      public void Init(System.Web.HttpApplication context)
      {
      context.BeginRequest += (new EventHandler(this.Application_BeginRequest));
      }
      public void Dispose()
      { }

      private void Application_BeginRequest(object source, EventArgs e)
      {
      HttpApplication application = (HttpApplication)source;
      HttpContext context = application.Context;
       
      if (context.Request.UrlReferrer == null ||
      context.Request.UrlReferrer.Host.Length == 0 ||
      context.Request.UrlReferrer.Host.ToLower() != context.Request.Url.Host.ToLower())
      {
      string extension = (Path.GetExtension(context.Request.PhysicalPath)).ToLower();
      if (Global.ALLOWED_IMAGE_EXTENSIONS.Contains(extension))
      {

      //context.Response.Redirect("~/Error.aspx?text=WOW!!!");
      Stream stream = GetStolenImage(context.Request.PhysicalPath);
      context.Response.Clear();
      context.Response.ClearContent();
      context.Response.ContentType = "image/jpeg";
      //context.Response.Cache.SetCacheability(HttpCacheability.Public);
      context.Response.BufferOutput = false;
       
      const int buffersize = 1024 * 16;
      byte[] buffer = new byte[buffersize];
      int count = stream.Read(buffer, 0, buffersize);
       
      while (count > 0)
      {
      context.Response.OutputStream.Write(buffer, 0, count);
      count = stream.Read(buffer, 0, buffersize);
      }
      stream.Close();
      }
      else if Global.ALLOWED_FILE_EXTENSIONS.Contains(extension))
      {
      // TODO : implement some session thing
      // context.Response.StatusCode = 403;
      }
      }
      }

     

    I want to show stolen image instead of orginal image. But If  I uncomment Response.Redirect() then that downloader downloads that Error.aspx...any idea to solve this ?

    thanks
     

    Wednesday, June 17, 2009 12:14 AM

Answers

  • User437720957 posted

     Start by simplifying the code to use TransmitFile or RewritePath to return a different image.

    Also, note that UrlReferrers can never be trusted. They may be missing from browsers and they may be added by downloaders.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 17, 2009 12:01 PM

All replies

  • User437720957 posted

     Start by simplifying the code to use TransmitFile or RewritePath to return a different image.

    Also, note that UrlReferrers can never be trusted. They may be missing from browsers and they may be added by downloaders.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, June 17, 2009 12:01 PM
  • User1493956762 posted

    so what should I use instead ? 

    Wednesday, June 17, 2009 12:14 PM
  • User437720957 posted

    There is no fool proof method. Many, if not most, downloaders copies user agent, cookie and referrer data from the browsers which invokes them, making it impossible to distinguish between a downloader and a real browser.

    I'm not saying that you should stay away from the method, just know its limitations.

    Wednesday, June 17, 2009 12:25 PM
  • User1493956762 posted

     [:'(]

    Wednesday, June 17, 2009 12:29 PM
  • User437720957 posted

    Hush, hush, don't cry...

    What is the actual scenario you're trying to prevent. What kind of page? What kind of theft?

    Wednesday, June 17, 2009 12:32 PM
  • User1493956762 posted

    I've lots of designs I've made and I do not want anybody can use it except ma site. I know it sounds crazy but I'm tryin' to reduce the theives as far as I can.

    Thanks mate for info. 

    Wednesday, June 17, 2009 12:40 PM
  • User437720957 posted

     So you want to prevent hot linking or batch downloading?

    You can still use the host name check you have in your code, since a non-empty UrlReferrer from a different host is a rather good indication of a malicious hot link.

    Wednesday, June 17, 2009 12:54 PM
  • User1493956762 posted

    Yes, something like that

    Wednesday, June 17, 2009 1:23 PM
  • User1662172693 posted
    Hi there,

    I am working on a similar solution myself in the following thread:

    http://forums.asp.net/p/1436710/3240528.aspx

    I believe I have a working solution. However, it is has not been tested with a downloader. The code is below:



    public class FileProtectionHandler : IHttpHandler, IRequiresSessionState
    {
       
        Helper helper = new Helper();
       
        public bool IsReusable {
            get { return true; }
        }
       
        public void ProcessRequest(System.Web.HttpContext context)

        string filename = context.Server.MapPath(context.Request.FilePath);
        IO.FileInfo fileinfo = new IO.FileInfo(filename);
        if (context.Request.ServerVariables("HTTP_REFERER") == null) {
            context.Response.WriteFile(context.Server.MapPath("no.jpg"));
            context.Response.End();
        }
        else {
            string domain = context.Session("Domain");
            if (!context.Request.ServerVariables("HTTP_REFERER").Contains(domain)) {
                // not my website
                context.Response.WriteFile(context.Server.MapPath("~") + "/static/img/no.jpg");
                context.Response.End();
            }
            else {
                string x = domain + "static/img/";
                if (context.Request.UrlReferrer.ToString.Contains(domain + "static/img/")) {
                    context.Response.ContentType = helper.GetContentType(context.Server.MapPath("no.jpg"));
                    context.Response.WriteFile(context.Server.MapPath("no.jpg"));
                    context.Response.End();
                }
                else {
                    context.Response.ContentType = helper.GetContentType(filename);
                    context.Response.WriteFile(filename);
                }
            }
        }
    }
    }


    I can post the whole class and helper functions if you want them. If nothing else, I hope that it will help you in your quest :).

    Hth,

    Stuart B.
    Wednesday, June 17, 2009 3:10 PM
  • User437720957 posted

     I suggest that you use TransmitFile instead of WriteFile, since it's much more efficient.

    Wednesday, June 17, 2009 4:17 PM
  • User1493956762 posted

    Yes exactly, I thought to use Session. But there is something I wanna tell, If browser opens any static image link then everything works but downloaders never care about what we're writing either through Response or Response.OutStream. AFAI got to know that there is some methods or events called that gives the exact image to downloader or something else. I mean if I write like this

    context.Response.BufferOutput = false;

    then browser reads what we're writing but if that value set to true, browser also do not care what we're writing.

    So, in all experiments I got the best way is to throw an exception that directly kicks on downloader ugly face.

    Wednesday, June 17, 2009 9:22 PM