Védekezz a képeid lopása ellen!

Vannak oldalak, ahol a tartalom legfontosabb elemei a képek. Ebbe a típusba tartozik egy fotós portfólióját bemutató weblap, vagy egy fotó-blog is. Az ilyen lapok üzemeltetőinek meglehetősen kellemetlen élmény szembesülni azzal, ha a képeiket más oldalakba illesztik be. A képek még a saját szerverünkről töltődnek le, azt terhelik, de a „tollak” már másvalaki honlapját ékesítik. Ez a hotlinking, amire nem tudok jó fordítást. Ma már a képkeresők is élnek a hotlinking lehetőségével, és ezzel szemben egy webmester szinte tehetetlen. Szinte … egy lehetséges megoldást azért leírok.

Hotlink védelem

Mit tehetünk akkor mégis?

További szócséplés helyett inkább leírok egy-két konkrét példát arra, hogy miképp védekezhetünk a képeink hotlinkelése ellen. Az alábbiak már megjelentek egy fórum hozzászólásomban, de úgy gondolom helyük van ebben a blogban is.

Egy alap hotlinking védelem

A védendő jpeg képek a /images mappában vannak. Ha a képet más oldalba illesztik be, azaz a kérésben a HTTP Referer nem a saját lapunkra mutat, vagy üres, akkor az eredeti kép helyett a /donothotlink.jpg kép kerül megjelenítésre.

# .htaccess
RewriteEngine   on
RewriteBase     /
RewriteCond     %{HTTP_REFERER}   !^http://www\.example\.com     [NC]
RewriteCond     %{HTTP_REFERER}   !^$
RewriteRule     ^images/.*\.jpg   /donothotlink.jpg    [L]

 

Problémák a fenti megoldással

  • Több böngésző nem küldi el az RFC 2616 szabványban előírt Referer headert. Vannak olyan, nagy siteok, amelyekről a legtöbb böngésző nem ad át Referer-t. (Kitaláljátok melyek?)
  • Egy egyszerű, hotlinkelésre figyelmeztető kép nem biztos, hogy ráveszi az embereket az oldalad megtekintésére.

Kicsit továbbgondolt, jobb megoldás

A fentinél az alábbi megoldás kicsit jobb eredményt ad, mert a látogató az eredeti kép vízjelezett és kicsit rontott minőségű, de azonos méretű verzióját kapja meg, ami alapján már eldöntheti, hogy el akar-e látogatni a lapra. A megoldáshoz a .htaccess hozzáférés mellett GD támogatott PHP futtatási lehetőségre van szükség.

# .htaccess
RewriteEngine   on
RewriteBase     /

RewriteRule     ^.*\.html     -       [L,CO=shield:yes:www.example.com:15:/]  [NC]
RewriteRule     ^$            -       [L,CO=shield:yes:www.example.com:15:/]

RewriteCond     %{HTTP_USER_AGENT}      !(bot|crawler|spider|slurp|pinterest|facebook|feedfetcher)   [NC]
RewriteCond     %{HTTP_REFERER}         !^http://www\.example\.com                                   [NC]
RewriteCond     %{HTTP_COOKIE}          !shield=yes     [NC]
RewriteRule     ^images/.*\.jpg         /protect.php    [L]

 

A fenti példában .htaccess fájl a főoldal (http://www.example.com/ és minden .html kiterjesztést tartalmazó lekérés esetén beállít egy shield nevű cookiet (yes) 15 perces élettartammal. Ezután minden /images könyvtárból történő kép letöltésekor ellenőrzi a shield cookie tartalmát, ha nincs meg, és a referer sem a mi oldalunkra mutat, akkor a kép helyett az alábbi protect.php fájl kapja meg a kérést. A robotoktól érkező kéréseket nem bántjuk.

<?php
// protect.php

$c_watermark = "images/watermark.png"; // áttetsző PNG kép
$c_watermark_size = "100"; // kitöltési szélesség százalékban
$c_watermark_color = array(0,0,0,40); // a teljes képre húzott háttérszín (RGBA)
$c_protectdir = "images"; // a védendő képeket tartalmazó könyvtár
$c_protected_image_quality = "50"; // jpeg minőség százalékben

if (preg_match("/^\/(".preg_quote($c_protectdir,"/")."\/.*\.jpg)/",$_SERVER['REQUEST_URI'],$matches)) {
        $picture = $matches[1];
        if (!file_exists($picture)) {
                header("HTTP/1.1 404 Not Found");
                exit;
        } else if (file_exists($picture.".protected")) {
                $jpgdata = file_get_contents($picture.".protected");
        } else {
                $source = imagecreatefromjpeg($picture);$s_width = imagesx($source);$s_height = imagesy($source);
                $color = imagecolorallocatealpha($source, $c_watermark_color[0], $c_watermark_color[1], $c_watermark_color[2], $c_watermark_color[3]);
                imagefilledrectangle($source,0,0,$s_width,$s_height,$color);
                $watermark = imagecreatefrompng($c_watermark);$w_width = imagesx($watermark);$w_height = imagesy($watermark);
                $d_width = round($s_width * $c_watermark_size / 100);$d_height = $d_width * $w_height / $w_width;
                imagecopyresampled($source, $watermark, round(($s_width - $d_width) / 2), round(($s_height - $d_height) / 2), 0, 0, $d_width, $d_height, $w_width, $w_height);
                imagejpeg($source,$picture.".protected");
                $jpgdata = file_get_contents($picture.".protected");
        }
} else {
        header("HTTP/1.1 403 Forbidden");
        exit;
}

header("HTTP/1.1 200 OK");
header("Content-type: image/jpeg");
header("Cache-Control: no-cache, no-store, must-revalidate");
header("Pragma: no-cache");
header("Last-Modified: ".date('r'));
header("Expires: ".date('r',time()-3600));
header("Accept-Ranges: none");
header("Content-Length: ".strlen($jpgdata));
print $jpgdata;

?>

 

A fenti kód vesz egy félig átlátszó png képet (watermark.png), majd a tartalmát szükséges nagyítás/kicsinyítés mellett az eredeti jpeg képre másolja. Ilyen áttetsző képet GIMP-pel vagy egyéb képszerkesztővel pillanatok alatt készíthettek. A fenti példa az áttetsző png képet átméretezi úgy, hogy az eredeti kép szélességét 80%-ban töltse ki, ez kerül az eredeti kép alsó részére. Hogy ne kelljen minden egyes letöltéskor megtenni ezt, az elkészült képet el is menti az eredeti kép mellé egy .protected kiterjesztés hozzátéve az eredeti fájlnévhez. Ha újra érkezik kérés, és már létezik ez a .protected fájl, akkor csak átadja ezt a böngészőnek. A félig átlátszó képre érdemes egy rövid szöveget tenni, melyben tájékoztatjuk a látogatót, hogy az eredeti képet a lapunkon érheti el. A képet nem engedjük cachelni, hogy a lapunkra látogatva azonnal megkaphassák az eredeti képet.

Vízjel

Már csak egy apró javascript van, amit a html lapok <head> szakaszába lehet illeszteni, ez akkor segít, ha a lapunkat egy iframe-ben is megnyitják, mert ebben az esetben a javascript törli a képhez hozzáférést adó cookie-t.

<html>
  <head>
    <script type="text/javascript"><!-- //
if (top != self) document.cookie = 'shield=no; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/';
    // --></script>
  </head>
  <body>
    <div>
      <img src="/images/protected.jpg" alt="Protected image"/>
    </div>
  </body>
</html>

 

A fenti kódot lehet és érdemes is fejleszteni, pl. logolással és egyéb praktikákkal.

Hotlinking védelem

Osszátok meg, fejlesszétek tovább!