Hlavní navigace

Jak zobrazit banner na zabezpečené stránce

Jakub Vrána

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.

Ú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

Našli jste v článku chybu?

3. 1. 2008 6:27

Session?? To by se server zbláznil, při asi 30 mega požadavcích za den.

4. 1. 2004 23:52

Jirka Kosek (neregistrovaný)

Kudy člověk chodil jde v rámci jednoho webu celkem pohodlně zjistit i z logu web serveru.

Myslím, že spoléhat na referer v aplikaci není moc dobrý nápad, protože stále více "bezpečnostních sw" typu "xyz firewall" filtruje HTTP provoz pro bezpečí a soukromí uživatele a součástí tohoto filtrování je i zahazování HTTP refereru. Pokud to aplikace opravdu potřebuje, je lepší si zdrojovou stránku předávat jako parametr v URL nebo skryté pole formuláře nebo v session proměnné. Nejlépe si to ještě na…

DigiZone.cz: Co chtějí operátoři při přechodu na DVB-T2?

Co chtějí operátoři při přechodu na DVB-T2?

Lupa.cz: Kdo pochopí vtip, může jít do ČT vyvíjet weby

Kdo pochopí vtip, může jít do ČT vyvíjet weby

DigiZone.cz: ČT láká na jarní programové tipy

ČT láká na jarní programové tipy

Měšec.cz: Jak levně odeslat balík přímo z domu?

Jak levně odeslat balík přímo z domu?

Podnikatel.cz: 3, 2, 1..EET startuje. Na co nezapomenout?

3, 2, 1..EET startuje. Na co nezapomenout?

Podnikatel.cz: Chaos u EET pokračuje. Jsou tu další návrhy

Chaos u EET pokračuje. Jsou tu další návrhy

Měšec.cz: mBank cenzuruje, zrušila mFórum

mBank cenzuruje, zrušila mFórum

Vitalia.cz: Když přijdete o oko, přijdete na rok o řidičák

Když přijdete o oko, přijdete na rok o řidičák

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

120na80.cz: Co všechno ovlivňuje ženskou plodnost?

Co všechno ovlivňuje ženskou plodnost?

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Lupa.cz: Teletext je „internetem hipsterů“

Teletext je „internetem hipsterů“

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

Vitalia.cz: Jmenuje se Janina a žije bez cukru

Jmenuje se Janina a žije bez cukru

Podnikatel.cz: Udávání a účtenková loterie, hloupá komedie

Udávání a účtenková loterie, hloupá komedie

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání

Podnikatel.cz: Chtějte údaje k dani z nemovitostí do mailu

Chtějte údaje k dani z nemovitostí do mailu