74

It's an important security issue and I'm sure this should be possible.

A simple example:

You run a community portal. Users are registered and upload their pictures. Your application gives security rules whenever a picture is allowed to be displayed. For example users must be friends on each sides by the system, in order that you can view someone else's uploaded pictures.

Here comes the problem: it is possible that someone crawls the image directories of your server. But you want to protect your users from such attacks.

If it's possible to put the binary data of an image directly into the HTML markup, you can restrict the user access of your image dirs to the user and group your web application runs of and pass the image data to your Apache user and group directly in the HTML.

The only possible weakness then is the password of the user that your web app runs as.

Is there already a possibility?

Joern Akkermann
  • 3,542
  • 8
  • 33
  • 41

6 Answers6

122

There are other (better) ways, described in other answers, to secure your files, but yes it is possible to embed the image in your html.

Use the <img> tag this way:

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

Where the xxxxx... part is a base64 encoding of gif image data.

bmb
  • 6,058
  • 2
  • 37
  • 58
  • so xxxxxxxxxx is for the to_blob/read/to_binary command / for the binary data of the image? and must there be an "=" in the end? – Joern Akkermann Mar 12 '10 at 03:20
  • You will have to convert your binary data to base64 encoding. The result is a string of printable characters that will usually end in 1 or 2 "=" symbols, according to the base64 spec. You will need to replace the xxx's with that string, all on one line. – bmb Mar 12 '10 at 05:37
  • 1
    I run IE tests always with the standard version that is shipped with Windows XP - I guess still many people use it... – Joern Akkermann Mar 12 '10 at 19:29
  • Some older browsers (IE7-IE9) have [limitations](https://en.wikipedia.org/wiki/Data_URI_scheme#Disadvantages) – mgutt Mar 27 '15 at 21:58
  • 1
    I don't know how I stumbled across this old question/answer, but it's important to note that this is not *binary* as the *OP* mentioned. This is base64 ASCII encoding. The source was originally binary. – vol7ron Apr 06 '16 at 18:50
  • Found this conversation because I was looking for the same thing. The solution from @bmb just works great! Thanks. – Steevie Aug 31 '16 at 07:42
  • 1
    Should mention that they're called data urls – FluorescentGreen5 May 16 '17 at 05:52
15

If I needed security on my images directory I wouldn't expose the directory at all. Instead my img src attributes would reference a page that would take a userid and an image id as a parameter.

The page would validate that that user did indeed have access to see that picture. If everythings good, send the binary back. Otherwise send nothing.

for example:

<img src="imgaccess.php?userid=1111&imgid=223423" />

Also, I wouldn't use guessable id's. Instead sticking to something like base 64 encoded guid's.

NotMe
  • 87,343
  • 27
  • 171
  • 245
  • +1, good answer, but if your code validates the user's access, should it matter if the IDs are guessable? – bmb Mar 12 '10 at 01:53
  • +1 What would you think about doing some .htaccess magic and outputting something like src="userid/user-image/" and, treating that as a directory, lock or unlock it on a per-user basis? –  Mar 12 '10 at 02:39
  • but then I have binary data in the src="" part. and I would take the userid from the current session, that's more secure. – Joern Akkermann Mar 12 '10 at 03:17
  • @bmb: It wouldn't matter so much about the file id's. However, it would for member id's. – NotMe Mar 12 '10 at 14:04
  • @D_N: That sounds like an interesting approach. I'm not too familiar with the linux side of things, so it's hard to comment. – NotMe Mar 12 '10 at 14:06
  • @Joern Akkermann: I'm not sure why you'd have binary data in the src part... However, taking the userid from session is a valid approach. I tend to stay away from any session variables myself which is why I said put the userid in the src tag. – NotMe Mar 12 '10 at 14:08
  • 1
    I'm surprised it's been so long and no one told you that you introduce a security vulnerability of local-file inclusion when you use PHP in this manor. It can lead to a remote-code execution exploit. – Steve Kline Nov 14 '17 at 21:52
4

I'm not sure I understand, but here goes. Instead of serving up static images that reside in an images folder - why couldn't you, using your server side technology of choice, have the images dynamically sent down to the client? That way your server side code can get in the mix and allow or deny access programmatically?

<img src="/images/getImage.aspx?id=123353 />
Eric
  • 3,284
  • 1
  • 28
  • 29
2

You could move the pictures out of the document root into a private directory and deliver them through your application, which has access to that directory. Each time your app generates an image tag, it then also generates a short-lived security token which must be specified when accessing a particular image:

<img src="/app/getImage.xyz?image=12345&token=12a342e32b321" />

Chances are very rare that someone will brute force the right token at the right time with the right image. There are at least to possibilities to verify the token in "getImage":

  1. Track all image tags in your app and store records in a database which link the randomly generated tokens and image IDs to the requesting users. The "getImage" action then checks the supplied parameters against that database.
  2. Generate the token as a checksum (MD5, CRC, whatever) over the user ID, the image ID and maybe the current day of the year, and be sure to mix in an unguessable salt. The "getImage" action will then recompute the checksum und check it against the specified one in order to verify the user's access. This method will produce less overhead than the first one.

PHP example:

$token = md5($_SESSION['user_id'].' '.$imageID.' '.$SECRET_SALT.' '.date('z'));
the-banana-king
  • 509
  • 2
  • 9
  • Thinking this over I find that it is easier to just apply the access constraints of the referencing HTML page again to the "getImage" action as someone wrote above. Nevertheless the checksum method may reduce the performance impact since it does not access any external resources to verify the request. – the-banana-king Mar 12 '10 at 02:21
  • Thanks for this. I had not realized that I could simply parse a query parameter name token on my Express server middleware where I checked if the user was authenticated with their token... This is much cleaner than needing to perform an explicit GET request, then figuring out how to properly load the binary image data into the img HTML tag.... Doing it this way looks more like a proper API / like how Google Maps requires users provide them an access token, ie. – user3773048 Jan 08 '19 at 04:53
0

With HTML5 you could use the canvas tag and JavaScript to do this.

You could perhaps do something with either CSS or a table layout to draw a picture (probably really bad performance, resolution, portability).

Either way, there is no stopping people from taking your pics. They could take a screenshot and crop it out.

As Chris mentioned in his answer, having long picture id's so that the URL for each image is not easy to guess or brute force is important. And no directory listing on your webserver directories is also.

Sean A.O. Harney
  • 23,901
  • 4
  • 30
  • 30
-1

https://www.base64-image.de/

I used this website to generate base64 code fir given image, and then this website provide code to directly paste . It worked.

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31063566) – Lajos Arpad Feb 19 '22 at 15:44