Monitor image access AND/OR prevent direct access

2019-09-01 07:47发布

I want users to see an image as part of a web page but I want to avoid them accessing a image directly. This could, say, give clues in the URL about what user they're linked to (a flaw I've seen in one facebook application).

How can I go about monitoring image access and/or preventing direct access to images (through url rewriting for example...)?

Solutions suggested so far:

  • Use of headers (reliable?)
  • Making access to images more difficult (ex: set image as div background).
  • ...

4条回答
唯我独甜
2楼-- · 2019-09-01 08:14

If I may, something that again isn't bullet-proof, but tricks many is to use the image as a background. In your HTML place an image tag filled with a special transparent 1px by 1px gif (blank.gif circa html table layouts) and size it to the dimensions of your actual image. Then set the background image of it to be the actual image. This will trick many users who only know how to right click to download/get the URL of an image.

<html>
<head>
    <style>
        #logo { background: url(my-logo.png); width: 100px; height: 50px; } /* Change this to match your image name and dimensions */
    </style>
</head>
<body>
    <img src="blank.gif" id="logo">
</body>
</html>

I know this won't help if the user Print Screens (but neither will any method), but it is a solution for those less knowledgeable users. Plus, sites like Youtube already employ this method so if it's good enough for Google, I'd say it's good enough for you or me!

EDIT: Please excuse my total lack of consciousness to this already being posted as a comment. I began writing before that was posted.

查看更多
Fickle 薄情
3楼-- · 2019-09-01 08:21

There is not bullet proof way. However, you can use heuristics. Inspect the following headers:

  1. Referer -- this header will be present is the image was requested by the browser as a result of <img> tag or CSS. This header will be empty if the image was requested directly (by typing the URL in address bar). If this header contains another domain then that other website hot-linked your image. Note that this is the expected behavior but it is not guaranteed that every browser will behave this way.

  2. Accept -- this header will contain a string such as image/* when image was requested because browser found it embedded in HTML tags or CSS. When someone requests the image directly by typing in the browser, you'll find values such as text/html,application/xhtml+xml etc. This is because browser does not know what to expect when it requests http://website.com/someimage.jpg; hence it will preferably ask for text/html content.

In Apache, you can check (and match) HTTP headers to determine whether content is accessible or not. I am not sure about other platforms, but you can write a generic proxy script for serving images.

Edit

If the image URL reveals information that you do not want disclosed, you can obfuscate it by using hashes or encryption. So instead of serving content such as:

<img src="/images/users/12345.jpg">

You will write:

<img src="/images/users/image.php?hash=<?php echo md5('secret' . '12345'); ?>">

You'll need to write a script that sends the corresponding image to the browser.

查看更多
【Aperson】
4楼-- · 2019-09-01 08:27

As said, there is not silver bullet for doing this (you can't prevent the user to make a screen capture for example)

But, if you want to protect your pictures against anonymous access, you can use a php "proxy" that will check if the user is allowed to see that pic, and then load it.

Here is a very simple sample code for such a proxy. If you really want to protect your images store them outside your document root.

<?php

//Sample image protection proxy. Do not use as is.

//Let's monitor the authorized accesses
session_start();
$mon = isset($_SESSION['mon']) ? $_SESSION['mon'] : 0;


//Let's simulate an auth mecanism
$allowed = isset($_GET['allowed']) ? (int)$_GET['allowed'] : 0;

if ($allowed === 1) {
    // DO NOT USE AS IS ! add security checks to prevent XSS, especially if images are uploaded by untrusted users
    $img = file_get_contents('img.png');
    $mon++;
    $_SESSION['mon'] = $mon;
    header('content-type:image/png');
    echo $img;
} else {
        //handle unauthorized access here.
    //For this example, I send some plain text
    header('content-type:text/plain');
    echo 'You are not allowed to see that picture.'.PHP_EOL;
    echo 'This picture has been opened : '.$mon. ' times.'; 
}
?>

If you want to test this script :

  • put it somewhere in your docroot
  • add a png image in the same folder. Name this image img.png.
  • to access the image, use http://url/of/the/script.php?allowed=1
  • to access the counter, remove the 'allowed' var.

Hope that helps !

查看更多
萌系小妹纸
5楼-- · 2019-09-01 08:31

Here's an idea that may work, although I've not really thought it through too much, and haven't tried it:

  1. Server receives a request for a page.
  2. Generate page content in PHP, using a one-time-key (OTK) that refers to the image. The OTK could be stored in a session variable or a database.
  3. When the client renders the page, the server receives a request via a query parameter for the image, using the OTK. Supply the image and delete the OTK.

For example, instead of:

<img src="www.mysite.com/mypage/myimage.jpg">

...generate a one-time-key and store that in a lookup table, so that it refers to your image:

4e33fd162fe95 => image.jpg

...then generate your page using that OTK instead:

<img src="www.mysite.com/mypage?image=4e33fd162fe95">

When the server receives a request for that image, send the image, and delete the OTK. This means that every request for the page generates a new OTK. Trying to use that URI for the image again will not work.

This has some obvious caveats in terms of performance, as client-side caching would no longer work, and it will place some overhead on the server. There are probably other caveats too.

查看更多
登录 后发表回答