Disable direct access to images
Asked Answered
B

2

10

I am making a little family photo album, with the intention to maybe open it to other people to store images later.

I upload the images to ~\images\, then resize them 3 times (Normal view ... thumbnail and a tiny version) and move them to ~\images\thumbs, ~\images\normal, ~\images\tiny and then move the original to ~\images\original.

If a user knows a file name, they can just goto http://mysite.com/images/normal/filename.jpg for direct access.

I'd prefer that not to be available to them.

So, is there a way to change the ImageUrl of the asp:Image control, to rather read from a non-accessable folder? And would this be a performance hit? I'm thinking something like (Not sure if it's possible) reading the image into s Steam, and somehow setting the ImageUrl or what ever, to read from the stream?

Hope you can assist.

Bipolar answered 2/1, 2012 at 23:54 Comment(0)
D
13

The answer is yes. You can use a special format of img src which will embed the image directly in the page.

Instead of the URL, you would use the following format:

<img src="data:image/png;base64,..." />

where data specifies the mime type of your image and the ... after base64, is the base64 encoded contents of the image.

This behavior is defined by this RFC.

Here is an example:

In the HTML:

<img id="MyPicture" runat="server" border="0" />

In the code-behind:

    protected void Page_Load(object sender, EventArgs e)
    {
        MyPicture.Src = @"data:image/gif;base64," + EncodeFile(Server.MapPath(@"/images/test.gif"));
    }

    private string EncodeFile(string fileName)
    {
        return Convert.ToBase64String(File.ReadAllBytes(fileName));
    }
Deracinate answered 3/1, 2012 at 0:8 Comment(11)
Thanks - I'm still lost. Do I still not need to specify the url to the image?Bipolar
Sorry was working on an example and got hung up on a dumb error. I have updated the answer, but it is img src, not href (working on too many things at once).Deracinate
This will hardly be cacheable.Gaggle
@CodeCaster: Cacheability was not indicated as a requirement in the question.Deracinate
Thanks - trying it now. Don't want caching due to an option to edit images, and I found I had to force refresh to see the changes.Bipolar
Would this increase page loading times or make an increase in server CPU?Bipolar
A qualified yes to both: because the images have to be converted to strings, there will be more data to process and deliver. Under normal circumstances, where caching would be used, you would see a greater impact, but since the files have to be retrieved and sent anyway, there is only a moderate impact. You could easily perform some local tests with and without this solution using fiddler (www.fiddler2.com), which will show you how long a page takes to load.Deracinate
OK, I hit a snag. It seems the image goes into the viewstate or something. The reason I say this is that when I click a menu item to leave the screen (a LinkButton), in Chrome, I notice 'Uploading 0% .. 100%'. It seems it submits the image source when I click a navigation or button. Can I disable this? - EDIT: Fixed, by setting Image1.ViewStateMode = ViewStateMode.Disabled;Bipolar
No, cacheability was not mentioned, since that can be implied. Unless mentioned otherwise, you want to use caching. And when suggesting a far from common solution (common one would be using hashes or other non-sequential ID's for the image filenames) one might draw attention to the cons and pros of that method.Gaggle
Just some FYI - RickNZ mentioned it only works on FF and IE8. I have tested it successfully on Chrome as well.Bipolar
@CodeCaster: Actually, no cacheability was implied in the question since the OP inquired about using a stream. This implication was confirmed in the OP's response to your comment above.Deracinate
P
0

Might I suggest considering something like:

  1. Save images to a folder like "siteroot/images/userid/".
  2. Upon successful log in set a session variable so that other pages will know that the current user is logged in. Session["user"] = youruser; Whatever object you store in your session variable include a valid youruser.userID that is pulled from a database.
  3. In your Global.asax file on your site's root add something like:

(untested code)

void Begin_Request(object sender, EventArgs e)
{
    //Protect /images/ folder for all requests
    if (Request.FilePath.Contains("images"))
    {
        YourUser user = Session["user"];

        if(user == null) {
            Server.Transfer("404.aspx"); //Folder not public
        }

        if (!Request.FilePath.Contains("images/" + user.userID.toString())){
            Server.Transfer("404.aspx"); //This is not current user's image folder
        }

    }
}

this should effectively deny access to everyone but the correct user of their respective "images" folder, even if they figure out the direct path of the image files.

If anyone has any ways to improve this method feel free to comment as I will soon be implementing this idea in a site and second opinions are always welcome.

Peplos answered 3/1, 2012 at 1:46 Comment(2)
Could a user not put mysite.com/images/user/1234/image.jpg into their browser though?Bipolar
they could, but if the correct user is not logged in then the server would simply return a file not found error, hence denying access to images that are not theirs, even if they figure out where on the server they are stored.Peplos

© 2022 - 2024 — McMap. All rights reserved.