Problém cross-frame scriptingu byl na tomto serveru diskutován již mnohokrát. Pravděpodobně nejlépe dané téma novým čtenářům osvětlí rozsáhlý článek
Píšeme bezpečnou webovou aplikaci.
Velmi zjednodušeně jde o problém vypisování cizího kódu stránkou v naší doméně. Takovýto kód pak má přístup ke všem objektům (cookies, ostatní framy) jako původní stránky. Internetové prohlížeče, jako například Internet Explorer, používají přitom k zabezpečení koncepci "stejné adresy serveru". Stránky z jedné adresy mají stejná bezpečnostní oprávnění, vložením kódu do jedné stránky tedy dojde k "ukořistění" celé používané domény.
Některé server-side skripty (resp. jejich interpreti) umožňují implicitně nastavit kontrolu vstupních proměnných a nahrazení některých citlivých znaků. Vlastní řešení má proti tomuto ale několik předností, především jde o maximální kontrolu nad použitými mechanizmy, kdy můžeme zabránit vstupu nejen jednotlivých znaků, ale i celých slov. Někdy je nutné zabránit vložení nesprávného SQL příkazu (před citlivé znaky dáme zpětné lomítko), někdy potřebujeme spíše zabránit výpisu většítek a menšítek (znaky < a > zaměníme za < a > v tomto pořadí), někdy je nutné provést obojí. Lehkou modifikací tohoto skriptu můžeme taktéž kontrolovat např. správnost http či e-mailové adresy, po zjištění chyby můžeme ihned přesměrovat prohlížeč na stránku s chybovou hláškou či špatnou hodnotu zapsat do logovacího souboru.
Že není velmi praktické v každém skriptu ručně ošetřovat hodnotu každé proměnné, je jasné. Vrhněme se tedy do programování knihovny, která tento problém řeší komplexně.
function Change(&$str, $From, $To, $End=""){
global $Changed;
$Changed=0;
$Str=" ".$str;
$UpStr=StrToUpper($Str);
$UpFrom=StrToUpper($From);
$UpTo=StrToUpper($To);
$LenFrom=StrLen($From);
while ($i=StrPos($UpStr,$UpFrom)) {
$UpStr=SubStr($UpStr,0,$i).$UpTo.SubStr($UpStr, $i+$LenFrom, 65530);
$Str = SubStr($Str, 0, $i).$To.SubStr($Str, $i+$LenFrom, 65530);
$Changed++;
}
if ($Changed==0) $End="";
$str=SubStr($Str, 1, 65530).$End;
return $str;
}
Předně je nutné udělat vlastí nahrazovací funkci. Ta zde uvedená není v mnoha ohledech ideální (např. neřeší problém záměny, kde nová hodnota obsahuje tu starou), nicméně pro tyto účely je krátká a efektivní. Pomocí té budeme nahrazovat jednotlivé nebezpečné znaky a řetězce.
function SafeVal($VarName) {
global $$VarName;
$SaveVal=$$VarName;
if ((Is_Array($$VarName)==false) && (true)) {
Change($$VarName,"<","<");
Change($$VarName,">",">");
Change($$VarName,"'",""");
Change($$VarName,"\"",""");
}
if ($$VarName!=$SaveVal) {
// zde by bylo zmiňované přesměrování
// nebo logování chyby
}
}
Funkce SafeVal Provede postupné nahrazení všech znaků v jedné proměnné. V případě nalezeného rozdílu původní a nové hodnoty se může něco provést. Funkce musí ošetřit, zda proměnná není typu pole, neboť v tomto případě by bylo nutné překonvertovat jednotlivé položky zvlášť.
function MakeSafe(&$VarArray){
$Polozka="";
$Hodnota="";
if(isset($VarArray)):
Reset($VarArray);
while(List($Polozka, $Hodnota) = each($VarArray)):
SafeVal($Polozka);
endwhile;
endif;
}
Následuje pravděpodobně nejdůležitější funkce. Má v parametru pole, jehož položky otestuje, popřípadě nahradí. Je nutné postupovat tak, aby se již nastavené defaultní proměnné typu $HTTP_USER_AGENT nepřepsaly, proto se názvy proměnných berou z tohoto asocativního pole, ale kontrolují se již nastavené hodnoty. V opačném případě by mohl kdokoliv zmiňované proměnné přepsat.
Nyní přijde již jen volání kontroly proměnných předávaných metodami POST, GET a COOKIES.
MakeSafe($HTTP_POST_VARS);
MakeSafe($HTTP_GET_VARS);
MakeSafe($HTTP_COOKIE_VARS);
Na závěr bych rád podotkl, že toto řešení je jen jedno z mnoha možných a má svoje výhody i nevýhody. Někdy je výhodnější použití mechanizmů intrerpreta skriptů, často je ale nutné si přidělat vlastní ošetření nad rámec toho zabudovaného.