sshot-33_thumb_1.pngThis post is a sequel to Keeping things private and will explain how to secure images so that only authenticated users can see them. This is relevant when you want to publish private album on the web. All image files in the web application are viewable by default, you can right-click any image to see information about it in the properties, you can load image into browser directly (just type in http://rtur.net/blog/pics/rssbutton.gif for example), you can download any image by saving it to the local drive etc. Obviously, with private albums you don’t want this kind of behavior.

Any directory can be configured to be not-browsable over IIS, but in the shared hosting environment your access to IIS can be severely limited. On the other hand, you can put your photos in the App_Data directory. This one is secured by default and IIS takes special care about files under data directory, which seems like a perfect fit for us. Small problem is – now this images hidden from everybody.

The solution is simple – we can load images on demand using good old Response.Write method and do it only for authenticated users. First thing, we need a helper page that will handle image load. It is an empty .aspx page, it takes image file name from the query string and, if user is authenticated, writes image to the page. Otherwise, user redirected to Login page. Content type derived from the file extension, and we only care about few image formats.

using System;
using System.Web;
using System.IO;
using System.Web.Hosting;
using BlogEngine.Core;

public partial class User_controls_GalleryImg : System.Web.UI.Page
{
    protected string photoDir = Path.Combine(BlogSettings.Instance.StorageLocation, @"photo\");
    protected void Page_Load(object sender, EventArgs e)
    {    
        photoDir = HostingEnvironment.MapPath(photoDir);

      if (!HttpContext.Current.User.Identity.IsAuthenticated)
            Response.Redirect(Utils.RelativeWebRoot + "Login.aspx");

        string fileName = Request.QueryString["src"];

        if (string.IsNullOrEmpty(fileName))
           fileName = Utils.RelativeWebRoot + "pics/pixel.png";
       else
           fileName = photoDir + fileName; 

        FileStream fileStream = new FileStream(fileName, FileMode.Open);
        int fileSize = (int)fileStream.Length;
        byte[] Buffer = new byte[fileSize];
        fileStream.Read(Buffer, 0, fileSize);
       fileStream.Close();
       Response.ContentType = ContType(fileName);       
        Response.BinaryWrite(Buffer);
    }

    protected string ContType(string fileName)
    {
        if (fileName.EndsWith(".jpg"))
            return "image/jpeg";
        else if (fileName.EndsWith(".gif"))
            return "image/gif";
        else if (fileName.EndsWith(".png"))
            return "image/png";
        else
            return string.Empty;
   }
}

Now, if you put this helper page in the application root and name it GalleryImg.aspx, authenticated users can view our photos using slightly different syntax:

http://yoursite.com/GalleryImg.aspx?src=rssbutton.gif

The difference with serving images regular way is pretty small, you can easily adopt any extension or user control used on your site as photo gallery to serve pictures this way. It took me literally five minutes to make Paul Tumelty’s user control serve pictures securely from the data directory. Next in line are Lightbox extension and Slideshow – to complete the system. Once this all set up and thoroughly tested, I’ll publish it here for download.

This is not the only way to secure image files, and probably not the most efficient one. You might look into Http handlers and other techniques. I took this approach because it is simple and portable – x-copy couple files and you good to go.