Autor Zpráva
Tomáš123
Profil
Ahoj diskusia, mám na starosti vytvoriť nejakým spôsobom niečo, čo zabezpečí, aby sa na neodsúhlasených weboch nezobrazoval spoplatnený obsah. Kontkrétne sa jedná o nejaké štatistiky, ktoré si budú môcť správcovia webov po zaplatení umiestniť na svoj web. Požadované je zobraziť to v <iframe>. Cieľom je vytvoriť nejaký systém, ktorý zabezpečí, že si obsah nebude môcť zobrazovať na svojom serveri bez platby hocikto. Nemalo by byť možné ani vymieňať nejaké súbory medzi webmi a užívať tak viac ako platiť. Skriptík mám premyslený, ale stojím na tom, ako získať meno servera, do ktorého sa načítava v <iframe> stránka so štatistikami. Vylúčil som tieto možnosti:
1. Cez $_SERVER['SERVER_NAME'] to nejde. Vracialo by to adresu servera, na ktorom je skript spustený.
2. Bolo mi navrhnuté, že nie je problémom, aby si klient musel pre funkčnosť umiestniť na svoj server nejaký súbor. To rozšírilo moje možnosti. Už som bol spokojný, že do src <iframu> pridám parameter s hodnotou názvu servera. Pri spracúvaní potom porovnám získaný názov s prideleným identifikátorom, ktorý by sa nachádzal v súbore na serveri klienta. Netrvalo mi dlho, kým som pochopil, že tým nikoho, kto pripojí prefíkanú hlavu, neogabem.

Chcel by som sa teda opýtať, či máte nejaké návrhy ako by šlo niečo také uskutočniť. Je nevhodné stavať to na JS, lebo to vôbec nezáleží od užívateľa.

Ďakujem vopred za pomoc.
Alphard
Profil
Tomáš123:
ale stojím na tom, ako získať meno servera, do ktorého sa načítava v <iframe> stránka so štatistikami
Podle mě v PHP není šance. Můžete pracovat výhradně s informacemi z http hlavičky. Tam by v $_SERVER['HTTP_REFERER'] někdy mohla být adresa nadřazené stránky, ale jisté to není. Lze to použít jako indikátor, ale musí to fungovat i bez něj.

Šlo by to řešit jednorázovými tokeny. Klientům (ověřeným tajným klíčem) přes API vygenerujte balík tokenů, které budou postupně zadávat do adresy webu iframu. Nezapomeňte přidat nějaký mechanismus, který umožní aktualizovat obsah iframe.
Keeehi
Profil
Pokud má klient zaplaceno, ta stránka bude posílat hlavičky
X-Frame-Options: ALLOW-FROM http://www.example.com
Content-Security-Policy: child-src 'self' https://www.example.com

pokud zaplaceno nemá, tak
X-Frame-Options: DENY
Content-Security-Policy: child-src 'none'

Není to stoprocentní ale velké skupině návštěvníků stránek klienta to zabrání zobrazení, pokud by se to klient pokusil dát i na jiný web než je www.example.com.



Je mmožné, že mi odtud zmizela podobná odpověď, kterou jsem psal před pár dny?
Tomáš123
Profil
Alphard:
Divná vec. Už druhýkrát som sa práve v momente pribudnutia príspevku chystal na doplnenie informácii :-).

Cez <iframe> to asi nepôjde... Vždy sa nájde aspoň riadok, ktorý musí byť na serveri klienta a stáva sa tak nedôveryhodný. Uvažoval som ale, či by nebolo možné vynútiť umiestnenie hotového skriptu ku klientovi s tým, že by hlásal domovskému serveru raz za platobné obdobie nejaké údaje. Mohol by som si viesť databázu serverov a kontrolovať, či neposielajú to isté ID. Neviem ale, či existuje možnosť ako dva servery hrajúce sa na jeden odlíšiť bez nutnosti spoliehať sa na klienta. Za predpokladu, že by kdesi v kóde existovalo $_SERVER['SERVER_NAME'] nie je problém prepísať to manuálne na adresu. Odstavil by som iba percento neznalých správcov.

Uvažujem, že by som mohol svoj skript u klienta natiahnuť domov a hľadať v ňom reťazec $_SERVER['SERVER_NAME']. Odstavím tak väčšie množstvo zlodejíčkov.

Klientům (ověřeným tajným klíčem) přes API vygenerujte balík tokenů, které budou postupně zadávat do adresy webu iframu.
Hmm, adresu spracujem a? Veď možnosť skopírovania adresy i identifikátoru stále existuje. Alebo som to zle pochopil? A kde má byť umiestnený ten tajný kľúč aby nebol kopírovateľný medzi webmi?

Nezapomeňte přidat nějaký mechanismus, který umožní aktualizovat obsah iframe.
Nerozumiem, <iframe> sa bude odkazovať na server, kde bude obsah stále aktuálny. Alebo máte na mysli nejaký refresh iba <iframu> podobne ako sa tu na diskusii dajú refreshnuť nové príspevky? Ak áno, na čo by mi to bolo?

Keeehi:
Nepostrehol som žiadnu reakciu odkedy som zverejnil otázku.

Ďakujem za ďalšiu možnosť, ale neviem ako podľa toho, či má niekto zaplatený obsah zmením, predpokladám, HTTP hlavičku.

Navyše by som zrejme musel pristaviť nejakú databázu s údajmi o platbe. A zas mi to vychádza tak, že by to, čo má ten web kedy posielať bolo umiestnené u klienta, čím sa z toho stáva nedôveryhodný zdroj. Ale nič o tom, neviem, toto je iba úvaha.
Alphard
Profil
Keeehi [#3]:
Problém, jak ho chápu já, je v autentizaci samotné. Tohle je až následný krok, na kterém příliš nezáleží (klidně by tam mohla být normální chybová hláška).

Je mmožné, že mi odtud zmizela podobná odpověď, kterou jsem psal před pár dny?
V logu moderátorských akcí pro toto vlákno nic nevidím. Nevíš, který den jsi to psal? Nechce se mi prohledávat http logy za víc dní :-)

Tomáš123:
Cez <iframe> to asi nepôjde... Vždy sa nájde aspoň riadok, ktorý musí byť na serveri klienta a stáva sa tak nedôveryhodný.
Proč? Mám takový pocit, že o této problematice moc nevíte. Zkuste si někde cvičně naimplementovat třeba přihlášení přes facebook. Věřím, že to pro vás bude inspirující.

či by nebolo možné vynútiť umiestnenie hotového skriptu ku klientovi
To mi nepřijde šťastné. Open source script, který si mohu verifikovat z pohledu bezpečnosti, bych si možná na web dal; ale otázka je, jestli by mi to stálo za to. Z pohledu řešení updateů a zpětné kompatibility je to pro vás myslím hodně špatné řešení.

Hmm, adresu spracujem a?
To je úplně jednoduché. Pokud je token platný, zpřístupní se obsah. Pokud je neplatný, odmítne se přístup (chybová hláška, nebo viz [#3] Keeehi).

Veď možnosť skopírovania adresy i identifikátoru stále existuje.
Právě proto je ten token jednorázový...

A kde má byť umiestnený ten tajný kľúč aby nebol kopírovateľný medzi webmi?
To už je problém každého webu. Prostě někde na serveru v konfiguraci.
Keeehi
Profil
Tomáš123:
Navyše by som zrejme musel pristaviť nejakú databázu s údajmi o platbe.
Ano.

A zas mi to vychádza tak, že by to, čo má ten web kedy posielať bolo umiestnené u klienta
Téhle větě nerozumím. Pokud se to vztahuje k té databázi, tak ta bude semozřejmě u vás.

Něco takového budeteš mít u sebe na serveru v souboru statistika.php
<?php
$paid = userHasPaid($_GET["id"]);
$allowedUrl = userAllowedURL($_GET["id"]);

header("X-Frame-Options: ALLOW-FROM ".$allowedUrl);
header("Content-Security-Policy: child-src 'self' ".$allowedUrl);
if ( !$paid  ) {
    echo "Obsah je nedostupný pro nezaplacení předplatného.";
    exit;
}
?>
Statistika, co se má zobrazovat jen po zaplacení

No a klient si dá na stránku kód
<iframe src="http://tvuj-web.cz/statistika.php?id=bflmpsvz"></iframe>
kde bflmpsvz je jeho identifikátor, který mu přidělíš.


Alphard:
Nevíš, který den jsi to psal?
Nevím, ale to už teď je jedno.
Tomáš123
Profil
Alphard:
Prioritne sa chcem brániť tomu, aby si klient, ktorý si prístup raz zakúpil nemohol skopírovať súbor s identifikátorom a src <iframu> na druhý web bez ujmy. Mám za to, že po vyriešení tohoto bude zabezpečené aj používanie súboru tretej strany bez jej vedomia.

Pokud je token platný, zpřístupní se obsah.
No a tu je tá otázka. Ako overiť, či ten token nepoužíva viac webov? Potreboval by som porovnávať názov servera s identifikátorom. Spracoval som riešenie, ktoré som vylúčil v [#1]:
<?php
    $_GET['host'] = (!empty($_GET['host']) ? "http://".$_GET['host']."/" : FALSE);
    $data_file = 'http://localhost/scripts/data-file.txt';
    $handler = fopen($data_file, 'r');
    $found = FALSE;
    if($handler !== FALSE && $_GET['host'] !== FALSE) {
        while(!feof($handler)) {
            $line = fgets($handler);
            list($host, $id) = explode("::", $line);
            if($host == $_GET['host']) {
                if(@file_get_contents($host."id_file.txt") == $id) {
                    $found = TRUE;
                }
            }
        }
    }
    if($found === TRUE) {
        echo "Tajný obsah";
    }
    else {
        echo "Smola!";
    }
?>
Funguje. Na tento script sa odkazujem takto: <iframe src="localhost/scripts/test1.php?host=localhost"></iframe>. Problémom je to, že ten údaj nie je vierohodný.

> Cez <iframe> to asi nepôjde...
> Proč? Mám takový pocit, že o této problematice moc nevíte.
Neviem. Ale za tie štyri dni mi všetko stroskotalo na tom, že za parameter adresy si môže každý dosadiť čo chce.

Keeehi:
Téhle větě nerozumím. Pokud se to vztahuje k té databázi, tak ta bude semozřejmě u vás.
Predstavoval som si to tak, že skript klienta bude posielať čosi ku mne.
Keeehi
Profil
Tomáš123:
No buď si nerozumíme a řešíte něco jiného, nebo jste kód z [#6] nevyzkoušel. Protože ty hlavičky téměř ideálně řeší to aby se obsah iframu načetl jen pokud je iframe na povolené doméně. Takže pokud to někdo zkopíruje na jiný web (jinou doménu), tak tam se mu to nezobrazí. Žádné jednorázové tokeny k tomu nejsou potřeba.
Alphard
Profil
Keeehi má pravdu. Já jsem hlavičku X-Frame-Options: ALLOW-FROM přesně neznal a nějak mi to nedošlo. Řešení je ve skutečnosti velmi jednoduché...
Tomáš123
Profil
Keeehi, Alphard:
Riešili sa tu dve metódy. Keďže platba pravdepodobne nebude vykonávaná cez nejaké API priamo na webe, nechcel som do toho ťahať databázu.

Kód som otestoval až dnes. Skript som upravil do nasledujúcej podoby:
<?php
function userHasPaid($id) {
    $id = (!empty($id) ? $id : FALSE);
    $data_file = 'http://www.online-ringtone-maker.com/data-file.txt';
    $handler = fopen($data_file, 'r');
    $found = FALSE;
    if($handler !== FALSE && $id !== FALSE) {
        while(!feof($handler)) {
            $line = fgets($handler);
            list(, $ID, $status) = explode("::", $line);
            if($ID == $id) {
                if(str_replace(array(" ", "\n", "\t"), "", $status) == 1) {
                    return TRUE;
                }
            }
        }
    }
    return FALSE;
}
function userAllowedURL($id) {
    $id = (!empty($id) ? $id : FALSE);
    $data_file = 'http://www.online-ringtone-maker.com/data-file.txt';
    $handler = fopen($data_file, 'r');
    $found = FALSE;
    if($handler !== FALSE && $id !== FALSE) {
        while(!feof($handler)) {
            $line = fgets($handler);
            list($host, $ID, ) = explode("::", $line);
            if($id == $ID) {
                return $host;
            }
        }
    }
    return FALSE;
}
$paid = userHasPaid($_GET["id"]);
$allowedUrl = userAllowedURL($_GET["id"]);

if ( !$paid || !$allowedUrl ) {
    echo "Obsah je nedostupný pre nezaplatenie predplatného.";
    exit;
}
header("X-Frame-Options: ALLOW-FROM ".$allowedUrl);
header("Content-Security-Policy: child-src 'self' ".$allowedUrl);
header("Expires: 0");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

echo "Spoplatnený obsah...";
?>
Potom som ho umiestnil na server a odkazoval sa naňho takto:
<iframe src=http://www.url.com/test.php?id=cislo></iframe>
Počítal som s tým, že po presunutí bloku podmienky o dva riadky vyššie docielim toho, že sa čosi vypíše aj v prípade neúspechu. Nevypísalo sa nič. A potom sa nič nevypísalo ani keď som to vrátil. O hlavičkách toho veľa neviem, možno sa niekam uložili a musel by som čosi premazať. Každopádne to obsah zobrazilo, aj keď som nepoužil svoje ID.

Snažil som sa odhaliť kde je chyba a príspevok som niekoľkokrát upravil podľa najnovších zistení. Súčasná verzia, teda kód vyššie, zobrazuje na localhoste a prvom serveri vetu o nedostupnosti a na druhom serveri vo Firefoxe nič (explicitne píšem) a v Chrome vetu o nedostupnosti. Možno som zle implementoval funkcie, možno musím vyčkať... Neviem.
Keeehi
Profil
Tomáš123:
header("X-Frame-Options: ALLOW-FROM ".$allowedUrl);
header("Content-Security-Policy: child-src 'self' ".$allowedUrl);

if ( !$paid ) {
    echo "Obsah je nedostupný pre nezaplatenie predplatného.";
    exit;
}
 
echo "Spoplatnený obsah...";

Řekněme, že v $allowedUrl je http://www.example.com
Potom pokud bude na stránce http://www.example.com/index.htm kód <iframe src=http://www.url.com/test.php?id=123></iframe>, mělo by se v něm zobrazit buď "Spoplatnený obsah" nebo "Obsah je nedostupný ..." v závislosti na tom, zad je zaplaceno nebo ne.
Když však stejnou stránku okopíruji na jiný web, tedy na stránce http://www.other-example.com/index.htm bude zase <iframe src=http://www.url.com/test.php?id=123></iframe>, tak tam se nezobrazí nic.


O hlavičkách toho veľa neviem, možno sa niekam uložili a musel by som čosi premazať.
Ano, hlavičky (a celé stránky) se můžou kešovat. Čemuž by mělo jít zabránit správnými metatagy nebo dalšími hlavičkami.
header("Expires: 0");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
Tomáš123
Profil
Keeehi:
Môj kód vyššie obsahuje chybu na riadku 10. Namiesto $id som chcel použiť $ID. Po úprave skript správne reaguje na nezaplatený prístup i neuvedenie parametru.

Když však stejnou stránku okopíruji na jiný web, tak tam se nezobrazí nic.
Mne sa v takom prípade nesprávne zobrazí spoplatnený obsah. Riadky v súbore data-file.txt vyzerajú takto:
http://localhost::123::1

mělo jít zabránit správnými metatagy
Prilepil som to do kódu (pred aj za ostatné hlavičky) a nič sa nezmenilo.
Keeehi
Profil
Tomáš123:
Mne sa v takom prípade nesprávne zobrazí spoplatnený obsah.
A testuješ to z jiné domény? Pokud máš tedy povoleno http://localhost, testuješ to třeba z http://another-localhost?
Teoretiky to může být způsobené prohlížečem. V jakém prohlížeči to stuješ? Jaká je jeho co nejpřesnější verze?

Prilepil som to do kódu (pred aj za ostatné hlavičky) a nič sa nezmenilo.
Poprvé ještě budeš muset smazat keš ručně, ale pak už by to mělo chodit. Proč ručně? Pokud si server stránku v keši, neptá se server a jen tu uloženou zobrazí. Nedozví se tak, že na stránka servíruje nové hlavičky.
Tomáš123
Profil
Keeehi:
A testuješ to z jiné domény?
Áno, mám jeden losalhost a prístup na dva weby kde som <iframe> umiestnil. Ak ID neexistuje, správne sa vypíše veta o nedosupnosti.

V jakém prohlížeči to stuješ?
Skúšal som to vo Firefoxe 43.0.1 a Chrome 47.0.2526.106 m.

Konkrétne sú iframy umiestnené na týchto adresách:
livestream.radioytb.com/test.php
www.online-ringtone-maker.com/test.html

Na druhej z nich sa mi na jednom z troch počítačov, na ktorých som testoval, zobrazil spoplatnený obsah aj napriek nesprávnemu no existujúcemu identifikátoru. Na ostatných počítačoch sa nezobrazilo nič.

Na prvom webe mi všetko funguje pekne. Skúsil som aj úplne vymazať záznam, v ktorom sa daný web spomína a skopírovať identifikátor druhého webu a správne sa nič nezobrazilo.

Neviem, či rozdiely vo funkčnosti neovplyvňuje konfigurácia serveru.

Tu je obsah súboru, v ktorom sú uložené údaje o identifikátoroch a platnosti:
http://localhost::123::1
http://online-ringtone-maker.com::456::1
http://livestream.radioytb.com::567::1
Kód v [#10] je upravený a aktuálny.

Poprvé ještě budeš muset smazat keš ručně, ale pak už by to mělo chodit.
Neviem, či sa to ukladalo do keše. Už reštart prehliadača menil niektoré veci.

Ešte mám malú otázočku bokom. Prečo si [#11] naspäť prehodil blok podmienky s hlavičkami?
yFang
Profil
Tomáš123:
V obou těch webech se mi zobrazuje Spoplatnený obsah....

Safari 9.0, V konzoli se píše:
Invalid 'X-Frame-Options' header encountered when loading 'http://www.online-ringtone-maker.com/test3.php?id=567': 'ALLOW-FROM http://livestream.radioytb.com' is not a recognized directive. The header will be ignored.
Unrecognized Content-Security-Policy directive 'child-src'.
Keeehi
Profil
Z livestream.radioytb.com/test.php to funguje, jelikož to povoluješ hlavičkou, z online-ringtone-maker.com to funguje, protože obojí je na stejné doméně.

Když na livestream.radioytb.com/test.php umístíš <iframe src="http://www.online-ringtone-maker.com/test3.php?id=456"></iframe> tak by se to mělo přestat zobrazovat.
Tomáš123
Profil
yFang, Keeehi:
V obou těch webech se mi zobrazuje Spoplatnený obsah....
Ďakujem za test. Správne by podľa nastavených identifikátorov aj malo. Len u mňa vo Firefoxe spomínanej verzie to kdesi viazne. V Chrome je to OK.

<neplatné po Keeehiho príspevku, ale mazať to nebudem>
Vo Firefoxe sa do konzoly vypísalo iba:
GET www.online-ringtone-maker.com/test.html [HTTP/1.1304 Not Modified 156ms]

U stránky livestream.radioytb.com/test.php už bol výpis členitejší.
</neplatné po Keeehiho príspevku, ale mazať to nebudem>

Je niečo chybné v tých hlavičkách, že to hlási chyby, alebo si to prehlidače rozdielne interpretujú? Záleží od jadra prehliadača (čo vysvetľuje funkčnosť v Safari i Chrome)? Teraz narážam hlavne na to, že sa výstupy naprieč prehliadačmi líšia. Dajme tomu, že inak je to funkčné.

Viem poskytnúť aj ostatné výpisy z konzoly, len to tu nechcem zamodriť viac než je nutné.
Keeehi
Profil
Tomáš123:
Je niečo chybné v tých hlavičkách, že to hlási chyby, alebo si to prehlidače rozdielne interpretujú?
Hlavičky by měly být správně. Jen zrovna tyto jsou celkem nové a tak je starší verze prohlížečů nemusejí znát. Ovšem dle caniuse CSP hlavičky ve verzi 1 zná 88% prohlížečů uživatelů a ve verzi 2 56%. Safari 9 má umí právě 1 a ne 2. Tudíž by bylo potřeba posílat starší verzi - frame-src

Ovšem udělal jsem chybu a vlastně místo child-src má být frame-ancestors. Protože to nemá být, co je do stránky vkládáno ale kam je vkládána.


Ještě by se dalo do toho prodělat podpora pro starší prohlížeče, které hlavičky neznají ale posílají referera. Čímž by měla jí rozšířit množina prihlížečů které to omezení postihne. Další, co by to mohlo přinést je, že se dozvíte na jakou "špatnou" URL to někdo nakopíroval a případně to nějak dál řešit.


To ale všechno za předpokladu, že to budou klienti vkládat z vašeho webu přes iframe. Pokud si však vytvoří proxyscript, tak vás neochrání nic. Jediné z čeho se to dá poznat je vysoký počet dotazů z jedné IP adresy. Což zase může klient maskovat posláním dotazů z různých IP adres, nebo keší za obětování aktuálnosti výsledků. Pokud mu to však bude stačit třeba jednou za hodinu, dostane se určitě po vaší rozlišovací schopnost. Zapojení keše zase může generovat určitou pravidelnost v datech, která by se dala detekovat. Proti tomu by se dala zase postavit keš s proměnlivou dobou kešování. V důsledku půjde tedy o to, kolik času jste s tím ochoten strávit vy a kolik ten, co se to bude snažit obejít. Začal bych tedy se základní ochranou a případně ji vylepšoval, pokud se ukáže že ji někdo nějak obchází.
Tomáš123
Profil
Keeehi:
Tudíž by bylo potřeba posílat starší verzi - frame-src
Ono, vo Firefoxe mi to stále nefunguje. Tento obsah by mal byť vrámci zabezpečenia dobre dostupný. Mohol by si mi teda pomôcť ešte s verziou pre staršie prehliadače?

I keď ostatné možnosti zabezpečenia znejú zaujímavo, nechcem to tu rozpitvávať a zbytočne to rozťahovať. Toto je vlastne moja prvá skúsenosť s hlavičkami a vysvetliť mi všetko pre tak pokročilé logovanie, filtrovanie a vyhodnocovanie by bol oriešok. Niečo si ohľadom toho pozriem, niečo skúsim, neskôr to možno budeme riešiť. Mimochodom, ďakujem za ten výpis. Sámemu by mi trvalo dosť dlho kým by som prišiel na toľko možných možností podvodu.

Predpokladám, že skripty budú dostatočne funkčné na to, aby nepodľahli menším útokom. Väčším spočiatku neodolajú, ale snáď to nebude tak zlé.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: