Hlavní navigace

Jak zobrazit banner na zabezpečené stránce

Když na stránce přenášené protokolem HTTPS chceme zobrazit banner, narazíme nejspíš minimálně na dva problémy. Článek popisuje, jak tyto problémy vyřešit pomocí PHP.

Tweetni to Odměnte autora  Jak to funguje?

Úvodem bych rád poznamenal, že článek popisuje řešení pro jeden konkrétní reklamní systém, ale s menšími úpravami by postup měl jít použít i pro jiné cizí objekty zobrazované na zabezpečených stránkách (kromě bannerů např. také počítadlo přístupů).

Když v reklamním systému BillBoard požádáte o kód banneru pro vložení na stránky, obdržíte zhruba toto:

<a href='http://ad2.billboard.cz/please/redirect/15102/1/1/1/'>
<img src ='http://ad2.billboard.cz/please/showit/15102/1/1/1/?typkodu=img' width='468' height='60'>
</a> 

Přesněji řečeno, toto je pouze kód z části <noscript>. O tom, proč je lepší se bez JavaScript kódu obejít, se zmíním na závěr.

Když tento kód vložíte na zabezpečenou stránku, setkáte se ve správně nakonfigurovaném prohlížeči s varováním, že stránka obsahuje i nezabezpečené položky, což je potenciální bezpečnostní riziko.

Než přistoupíme k řešení tohoto problému, chtěl bych zmínit o tom, že kdyby BillBoard poskytoval i verzi banneru přístupnou přes HTTPS (což ale stejně neposkytuje), k vyřešení problému by to příliš nepomohlo, protože by byl certifikát jeho serveru nejspíš vydán jinou certifikační autoritou a uživateli by se kvůli tomuto banneru opět mohlo zobrazit nějaké varování, čemuž se právě chceme vyhnout.

Zobrazení banneru

Naše řešení spočívá v tom, že na serveru vytvoříme skript, který stáhne obrázek banneru pomocí HTTP a pošle ho dál. Značku pro zobrazení banneru potom nahradíme za:

<img src='banner.php' width='468' height='60'> 

Kvůli tomu, že kód pro zobrazení banneru na serveru BillBoard nám nepošle rovnou obrázek, ale pouze přesměrování na něj, a také kvůli tomu, že se neobejde bez hlavičky Referer, nemůže být skript až tak jednoduchý jako např.:

<?php
readfile("http://ad2.billboard.cz/please/showit/15102/1/1/1/?typkodu=img");
?> 

Skript tedy může vypadat nějak takhle:

<?php
$billboard = "ad2.billboard.cz";
$banner = "15102/1/1/1/";
$fp = fsockopen($billboard, 80);
fwrite($fp, "GET /please/showit/$banner?typkodu=img HTTP/1.1\r\n");
fwrite($fp, "Host: $billboard\r\n");
fwrite($fp, "Referer: $_SERVER[HTTP_REFERER]\r\n");
fwrite($fp, "\r\n");

function find_image($fp, $line) {
  static $content_image = "";
  if (eregi("^Content-Type: image/", $line))
    $content_image = $line;
  elseif ($line === "") {
    if (!$content_image)
      return false;
    header($content_image);
    fpassthru($fp);
    fclose($fp);
    exit();
  }
  return true;
}

while (!feof($fp)) {
  $line = rtrim(fgets($fp, 1024), "\r\n");
  if (eregi("^Location: http://$billboard(.*)", $line, $regs)) {
    fclose($fp);
    $fp = fsockopen($billboard, 80);
    fwrite($fp, "GET $regs[1] HTTP/1.1\r\n");
    fwrite($fp, "Host: $billboard\r\n");
    fwrite($fp, "\r\n");
    while (!feof($fp)) {
      $line = rtrim(fgets($fp, 1024), "\r\n");
      if (!find_image($fp, $line))
        break; // nenarazili jsme na hlavičku Content-Type
    }
    break; // z nějakého důvodu se nám nepodařilo poslat obrázek
  }
  elseif (!find_image($fp, $line))
    break; // nenarazili jsme na hlavičku Content-Type
}
fclose($fp);

// skript nenašel reklamní obrázek
header("Content-Type: image/gif");
readfile("img/nic.gif");
?> 

Skript otevře připojení k serveru na port 80 (HTTP) a požádá ho o dokument s obrázkem. V hlavičce Referer mu předá URL dokumentu, na kterém se banner zobrazuje. Pak prochází hlavičky vráceného dokumentu, dokud nenarazí na přesměrování (hlavička Location). Jakmile na něj narazí, zavře původní připojení, otevře nové a vyžádá si dokument, na který byl přesměrován – to už by měl být obrázek s bannerem. Funkce find_image potom zjistí mime-typ obrázku, a jakmile skončí hlavičky, vypíše zbývající data. Skript bude pracovat i v případě, že na původní stránce nebude přesměrování, ale rovnou požadovaný obrázek. V případě, že se něco nepovede, skript místo požadovaného banneru zobrazí obrázek img/nic.gif.

Dlužno podotknout, že pro zajištění větší univerzálnosti by skript měl kromě hlavičky Content-Type přeposílat například také hlavičku Transfer-Encoding, ale pro zajištění lepší čitelnosti se na to ve skriptu nehledí. Možná vás napadlo, že po získání finální adresy banneru bychom mohli provést obyčejné readfile. To bohužel není možné proto, že z hlaviček potřebujeme získat Content-Type obrázku.

Tím je kód pro zobrazení banneru hotov, zbývá vyřešit obsluhu kliknutí na banner.

Kliknutí na banner

V okamžiku, kdy na takto zobrazený banner uživatel klikne, bude přesměrován na domácí stránku serveru BillBoard. Jak k tomu dojde? Banner se totiž samozřejmě zobrazuje pokaždé jiný a adresa http://ad2.bi­llboard.cz/ple­ase/redirect/15102/1/1/­1/ tedy není přesměrována na žádnou pevnou adresu. To, kam se tato adresa přesměruje, nastaví obrázek banneru v cookie. Pokud tedy chceme zajistit, aby fungovalo i kliknutí na banner, budeme muset tuto cookie od kódu pro zobrazení banneru získat a při kliknutí ji serveru opět poslat.

Změna v kódu pro zobrazení banneru nebude příliš složitá. Do funkce find_image přidáme tuto větev:

elseif (eregi("^Set-Cookie: bbcz=(.*); path=/please/redirect/$banner; domain=ad2.billboard.cz", $line, $regs))
  setcookie("bbcz", $regs[1]); 

Když skript narazí na cookie platnou pro adresu zajišťující obsluhu kliknutí, nastaví tuto cookie klientovi. Server BillBoard nastavuje více cookies, pro zajištění funkčnosti nám však stačí pouze tato.

Vzhledem k tomu, že tato cookie je platná pouze v rámci našeho serveru, budeme pro obsluhu kliknutí muset vytvořit skript, který ji serveru BillBoard přepošle. Mohli bychom to samozřejmě vyřešit i tak, že bychom při posílání cookie rovnou řekli klientovi, že je platná pro server BillBoard. Riskovali bychom však, že ji prohlížeč jakožto cookie třetí strany odmítne.

Kód pro zobrazení banneru včetně odkazu bude tedy nakonec vypadat nějak takhle:

<a href='banner_c.php'>
<img src='banner.php' width='468' height='60'>
</a> 

Vytvoření skriptu banner_c.php nebude s předchozími zkušenostmi nikterak složité:

<?php
$billboard = "ad2.billboard.cz";
$banner = "15102/1/1/1/";
$fp = fsockopen($billboard, 80);
fwrite($fp, "GET /please/redirect/$banner HTTP/1.1\r\n");
fwrite($fp, "Host: $billboard\r\n");
fwrite($fp, "Referer: $_SERVER[HTTP_REFERER]\r\n");
fwrite($fp, "Cookie: bbcz=". stripslashes($_COOKIE["bbcz"]) ."\r\n");
fwrite($fp, "\r\n");

while (!feof($fp)) {
  $line = rtrim(fgets($fp, 1024), "\r\n");
  if (eregi("^Location: (.*)", $line, $regs)) {
    header($line);
    break;
  }
  elseif ($line === "") {
    fpassthru($fp);
    break;
  }
}
fclose($fp);
?> 

Skript se připojí k serveru BillBoard, pošle mu hlavičku Referer a cookie získanou od klienta a v hlavičkách začne hledat přesměrování. Když ho najde, přepošle ho klientovi, když ne, vrátí klientovi tělo dokumentu.

Zamyšlení na závěr

Uvedený postup umožňuje na zabezpečeném serveru zobrazit banner třetí strany. Tím, že banner klientovi posíláme přímo z našeho serveru, deklarujeme, že svým certifikátem ručíme za jeho obsah. Popsaný postup bychom tedy měli používat velmi obezřetně. Článek popisuje, jak v prostoru vymezeném pro banner zobrazíme cizí obrázek. Ať už bude obrázek obsahovat cokoliv, nemůže dojít ke zmatení uživatele, protože se tento obrázek zobrazí v prostoru vymezeném pro reklamu. Ale například pouhé opomenutí rozměrů ve značce <img> by mohlo znamenat katastrofu, protože by nám záškodník mohl podstrčit obrázek přes celou obrazovku, který by mohl uživatele dokonale zmátnout – např. by ho mohl přimět k tomu, aby peníze za objednané zboží poslal na účet záškodníka. Z tohoto důvodu také článek popisuje pouze řešení bez využití JavaScriptu, protože při jeho využití by záškodník uživatele mohl zmást dočista.

Na samý závěr bych rád připomenul, že podle pravidel BillBoardu „je jakýkoli zásah do HTML kódu bez povolení provozovatele sítě nepřípustný“. Před aplikací uvedeného postupu je tedy vhodné si toto povolení vyžádat. Podobné pravidlo pravděpodobně budou mít i ostatní systémy.

Odkazy

Jakub Vrána

Jakub Vrána

Autor se živí programováním v PHP, podílí se na jeho oficiální dokumentaci, vyučuje ho na MFF UK a vede odborná školení. Poznámky si zapisuje na weblog PHP triky.

Ohodnoťte jako ve škole:
Průměrná známka 3,12
Tweetni to Odměnte autora  Jak to funguje?

Zabezpečení TCP/IP na Linuxu - třídenní workshop

V tomto praktickém workshopu se podíváme na počítačovou síť z hlediska zabezpečení. Předvedeme si vybrané druhy útoků a zkusíme si proti nim vytvořit obranu.

       

Přehled názorů

SSL varovani
Jerry III 30. 12. 2003 03:46
Nový
├ 
Re: SSL varovani
Michal Kara 30. 12. 2003 07:30
Nový
├ 
Re: SSL varovani
nishkam 30. 12. 2003 09:37
Nový
│
└ 
statistiky
met - Martin Hassman 30. 12. 2003 10:26
Nový
└ 
Re: SSL varovani
Jakub Vrána 30. 12. 2003 11:00
Nový
 
└ 
Re: SSL varovani
Michal Kara 30. 12. 2003 13:08
Nový
 
 
└ 
Re: SSL varovani
Jakub Vrána 30. 12. 2003 15:28
Nový
 
 
 
└ 
Re: SSL varovani
Michal Kara 30. 12. 2003 21:03
Nový
hlavicka v banner_c.php
Stepan Kasal 30. 12. 2003 11:37
Nový
└ 
Re: hlavicka v banner_c.php
Jakub Vrána 30. 12. 2003 11:42
Nový
 
└ 
Re: hlavicka v banner_c.php
mrk 30. 12. 2003 17:47
Nový
W3C & Billboard
czeXit 30. 12. 2003 12:08
Nový
└ 
Re: W3C & Billboard
Yeti 30. 12. 2003 14:53
Nový
 
└ 
Re: W3C & Billboard
czeXit 30. 12. 2003 15:53
Nový
Všechny zobrazené banery jsou z jedné adresy
Petr Ferschmann 30. 12. 2003 14:59
Nový
└ 
Re: Všechny zobrazené banery jsou z jedné adresy
Jakub Vrána 30. 12. 2003 15:33
Nový
Referer si blokuje každý správný paranoik
karel 30. 12. 2003 15:01
Nový
├ 
Re: Referer si blokuje každý správný paranoik
Yeti 30. 12. 2003 17:02
Nový
└ 
Re: Referer si blokuje každý správný paranoik
Michal Kara 30. 12. 2003 21:07
Nový
 
└ 
Re: Referer si blokuje každý správný paranoik
Jirka Kosek 4. 1. 2004 23:52
Nový
 
 
└ 
Re: Referer si blokuje každý správný paranoik
Martin Zvarík 3. 1. 2008 06:27
Nový
Povazuji to za velmi nebezpecne
Dan Ohnesorg 30. 12. 2003 19:25
Nový
├ 
Re: Povazuji to za velmi nebezpecne
Jakub Vrána 30. 12. 2003 22:39
Nový
│
└ 
Re: Povazuji to za velmi nebezpecne
Dan Ohnesorg 2. 1. 2004 00:12
Nový
│
 
└ 
Re: Povazuji to za velmi nebezpecne
Jakub Vrána 2. 1. 2004 15:58
Nový
└ 
Re: Povazuji to za velmi nebezpecne
runner 1. 1. 2004 19:51
Nový
toky dat + uzitecnost
TomasDean 30. 12. 2003 23:47
Nový
└ 
Re: toky dat + uzitecnost
Jakub Vrána 31. 12. 2003 10:03
Nový
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem