[PHP] HTTP header spoofing

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Svennetjee
  • Registratie: December 2007
  • Laatst online: 18:13
Hey,

laatst las ik een artikel over het gebruik van de $_SERVER variabelen 'SERVER_NAME' en 'HTTP_HOST'. Ik dacht eerst dat deze twee dezelfde functie hadden, maar na wat verder onderzoek blijkt de 'SERVER_NAME' het minst veilig te zijn. Zoals in het artikel te lezen is, zijn ze allebei echter makkelijk te misleiden.

Nu gebruik ik onderstaand script om HTTP header spoofing te detecteren, maar is dit genoeg? En zo nee, hoe zou ik het anders, beter, kunnen doen? En is zo'n header echt zo makkelijk te spoofen als in het artikel wordt voorgedaan?

PHP:
1
2
3
4
if(empty($_SERVER['HTTP_HOST'])) { $BASEPATH = htmlentities(addslashes($_SERVER['SERVER_NAME'])); } else { $BASEPATH = htmlentities(addslashes($_SERVER['HTTP_HOST'])); }
if(fsockopen($BASEPATH, 80, $errno, $errstr, 2)) {
define("BASEPATH", $BASEPATH);
} else { die('HTTP Header spoofing detected'); }


Edit: uhm, foutje in de code : )

Alvast bedankt ;)

[ Voor 4% gewijzigd door Svennetjee op 07-01-2009 20:34 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Over je code: Als HTTP_HOST leeg is, wil je de waarde juist gebruiken? 8)7 En addslashes tezamen met htmlentities?

Maar goed, de Host header is in weze vrije input door client en dat moge toch wel duidelijk zijn uit je link. Het kan niet meer basic dan met telnet wat headers tikken. ;)

{signature}


Acties:
  • 0 Henk 'm!

  • Room42
  • Registratie: September 2001
  • Niet online
HTTP is niets anders dan plain-text vraag en antwoord tussen client en server. Zie deze Wiki maar eens: Wikipedia: Hypertext Transfer Protocol

En plak onderstaande tekst maar eens in een telnet sessie op poort 80 naar www.google.com:
code:
1
2
3
GET / HTTP/1.1
<enter>
<enter>
(Dus met twee enters achter de eerste regel)
Het resultaat is een "moved" pagina, omdat de headers niet compleet zijn, maar je zou het bij wijze van spreken dus zelf kunnen typen. Daardoor zijn headers heel makkelijk te spoofen.

Maar die code van jou gaat zo niet werken, nee.

[ Voor 4% gewijzigd door Room42 op 07-01-2009 20:27 ]

"Technological advancements don't feel fun anymore because of the motivations behind so many of them." Bron


Acties:
  • 0 Henk 'm!

  • Svennetjee
  • Registratie: December 2007
  • Laatst online: 18:13
Ok, bedankt voor de informatie. Foutje in de code was idd dom, eventjes omgewisseld. En waarom zou je geen addslashes samen met htmlentities gebruiken?

Acties:
  • 0 Henk 'm!

  • Room42
  • Registratie: September 2001
  • Niet online
Je kunt ook !empty() gebruiken. Sowieso zou dit het denk ik leesbaarder maken:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
if (!empty($_SERVER['HTTP_HOST'])) {
    $BASEPATH = htmlentities(addslashes($_SERVER['HTTP_HOST']));
} else {
    $BASEPATH = htmlentities(addslashes($_SERVER['SERVER_NAME']));
}


if (fsockopen($BASEPATH, 80, $errno, $errstr, 2)) {
    define("BASEPATH", $BASEPATH);
} else {
    die('HTTP Header spoofing detected');
}

Dat maakt het fout-zoeken later makkelijker omdat php-errors altijd een regelnummer mee krijgen. Overigens is een time-out van 2 seconden wel erg kort.

En, maar dat is niet helemaal mijn afdeling, volgens mij maakt zo'n check je enorm gevoelig voor DoS aanvallen, omdat als men een niet bestaande server gebruikt als HTTP_HOST, je bij elke uitvoering een 2 seconden (of langer als je dat instelt) time-out krijgt, wat betekent dat het eenvoudig is om duizenden connections open te zetten.

[ Voor 27% gewijzigd door Room42 op 07-01-2009 20:48 ]

"Technological advancements don't feel fun anymore because of the motivations behind so many of them." Bron


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Svennetjee schreef op woensdag 07 januari 2009 @ 20:36:
[...] En waarom zou je geen addslashes samen met htmlentities gebruiken?
Omdat je doorgaans pas escaping toepast op het moment dat het noodzakelijk is, en op basis van de toepassing dan ook de geschikte escaping gebruikt. addslashes is nogal een domme generieke vorm van escaping waar voor de meeste toepassingen betere alternatieven zijn, en htmlentities is specifiek voor HTML output (maar is over het algemeen ook overkill, vaak voldoet htmlspecialchars prima). De combinatie van deze twee vormen van escaping is echter compleet onlogisch...

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Room42
  • Registratie: September 2001
  • Niet online
Plus dat je een met htmlentities & addslashes bewerkte hostname natuurlijk nooit met fsockopen geopend krijgt.

"Technological advancements don't feel fun anymore because of the motivations behind so many of them." Bron


Acties:
  • 0 Henk 'm!

Verwijderd

Waarom zou je daar in godsnaam htmlentities gebruiken? Dat is een functie die je gebruikt als je gegevens weer gaat geven in een HTML document. Dat lijkt me op dat punt in de code absoluut niet aan de orde. Hetzelfde geldt voor addslashes. Totdat je er iets mee gaat doen in een shell script of een SQL query, of iets anders waarin quotes een speciale betekenis kunnen hebben, moet je niks escapen. De magic_quotes_gpc meuk staat niet voor niet standaard uit tegenwoordig.

En dan nog. Als je gebruikt maakt van virtual hosts, komt er helemaal geen 'vreemde' waarde voor HTTP_HOST aan bij dat script, want dat zou geen enkele virtual hostname matchen. Dat kan alleen eventueel in de 'default virtual host'. De vraag is dus hoe druk jij je er in je script over moet maken.

In principe zijn die HTTP headers user input, dus mag je ze sowieso niet vertrouwen. Dat wil ook weer niet zeggen dat je alles bij voorbaat moet gaan escapen. Dat is een mug te lijf gaan met dynamiet.
Room42 schreef op woensdag 07 januari 2009 @ 20:53:
Plus dat je een met htmlentities & addslashes bewerkte hostname natuurlijk nooit met fsockopen geopend krijgt.
Wat zou er in een valide hostnaam geëscapet worden dan? Niets dus. Juist.

[ Voor 13% gewijzigd door Verwijderd op 07-01-2009 20:55 ]


Acties:
  • 0 Henk 'm!

  • Svennetjee
  • Registratie: December 2007
  • Laatst online: 18:13
Hmm, voor de fsockopen ga ik inderdaad een alternatief zoeken, reguliere expressie ofzo om te checken of de link valide is opgebouwd is of niet is eigenlijk al voldoende.

En ik ga er mee akkoord dat het gebruik van htmlentities en addslashes samen onlogisch is, maar uiteindelijk bereik ik wel het gewenste effect: een vervuilde header komt er dan niet meer in.. Zou jij wat anders aanraden om het te checken?

Edit:
Room42 schreef op woensdag 07 januari 2009 @ 20:53:
Plus dat je een met htmlentities & addslashes bewerkte hostname natuurlijk nooit met fsockopen geopend krijgt.
En dat is eigenlijk juist de bedoeling: er horen geen speciale tekens in die header te staan..

[ Voor 29% gewijzigd door Svennetjee op 07-01-2009 20:56 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Svennetjee schreef op woensdag 07 januari 2009 @ 20:55:

En ik ga er mee akkoord dat het gebruik van htmlentities en addslashes samen onlogisch is, maar uiteindelijk bereik ik wel het gewenste effect: een vervuilde header komt er dan niet meer in.. Zou jij wat anders aanraden om het te checken?
Bij een 'vervuilde' header moet je onmiddellijk je script afbreken en een foutmelding geven. Je moet zéker niet proberen iets te doen met 'opgeschoonde' waarden. Als iemand verkeerde headers stuurt, geef je ze een status code 400 (Bad Request) terug.

Acties:
  • 0 Henk 'm!

  • Svennetjee
  • Registratie: December 2007
  • Laatst online: 18:13
Hmm, je hebt gelijk. Als je het zo bekijkt doe ik het erg omslachtig. Ik ga het denk ik helemaal anders doen. Ik wilde die server variabele gebruiken om bestanden op de server dynamisch te includen, maar dan moet de variabele natuurlijk wel schoon zijn. Als ik bestanden dynamisch kan ikcluden, kan ik het heel makkelijk ook op een andere site zetten en gebruiken, en hoef ik alleen nog maar de inloggegevens voor mysql e.d. te veranderen. Ik zet de url wel gewoon hardcoded, kan niks aangepast worden. Header spoof controle laat ik nog wel staan, omdat ik dat sowieso niet graag wil hebben, maar op een andere manier.

Iig iedereen bedankt voor de nieuwe inzichten ;)

Edit:
Na enig speurwerk leek de reguliere expressie in de code het beste om een valide url te checken. Voldoet dit om foutieve headers te weren?

PHP:
1
2
3
4
5
6
7
8
9
10
11
if(!empty($_SERVER['HTTP_HOST'])) {
    if(!preg_match("/([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}/", $_SERVER['HTTP_HOST'])) {
        header("HTTP/1.1 400 Bad Request");
        exit();
    }
} else {
    if(!preg_match("/([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}/", $_SERVER['SERVER_NAME'])) {
        header("HTTP/1.1 400 Bad Request");
        exit();
    }
}

[ Voor 29% gewijzigd door Svennetjee op 07-01-2009 21:31 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Bestanden op dezelfde server includen doe je niet via http.
Bestanden op een andere server includen kan via http met een vaste url.

Nergens in bovenstaande verhaal hoef je in PHP iets met de binnenkomende Host header te doen. :Y)

{signature}


Acties:
  • 0 Henk 'm!

  • Svennetjee
  • Registratie: December 2007
  • Laatst online: 18:13
Voutloos schreef op woensdag 07 januari 2009 @ 21:31:
Bestanden op dezelfde server includen doe je niet via http.
Bestanden op een andere server includen kan via http met een vaste url.

Nergens in bovenstaande verhaal hoef je in PHP iets met de binnenkomende Host header te doen. :Y)
Hmm nee klopt, maar als <base> waarde in de html komt het bijvoorbeeld van pas. Maar zie bovenstaand voorbeeld, ik gebruik die dingen niet meer nu. Alleen nog even een check op valide headers.

Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
Svennetjee schreef op woensdag 07 januari 2009 @ 20:55:
Hmm, voor de fsockopen ga ik inderdaad een alternatief zoeken, reguliere expressie ofzo om te checken of de link valide is opgebouwd is of niet is eigenlijk al voldoende.
Ik snapte eerst die hele fsockopen al niet? Elke willekeurige bestaande hostname die antwoord geeft accepteer jij als goed?
Maar nu wil je met regex ofzo gaan checken of een hostname valid of invalid is?

Wat heb je eraan als je een valide hostname ingevuld hebt staan in $BASEPATH als je nog steeds niet weet of je het je eigen hostname is?

Ik zou maar eens gaan nadenken over waar je die $BASEPATH voor gebruikt, want als iemand er google.com ingeeft dan vind jij dit blijkbaar goed terwijl hij nog steeds gespoofd is.
Een simpele substr vanaf rechts ( zodat je wel subdomeinen ook accepteert ) met je eigen hostname lijkt me makkelijker en cpu-vriendelijker dan welke regex dan ook.
Svennetjee schreef op woensdag 07 januari 2009 @ 21:04:
Edit:
Na enig speurwerk leek de reguliere expressie in de code het beste om een valide url te checken. Voldoet dit om foutieve headers te weren?
Waarom in vredesnaam een regex? En helemaal zoals je het hier gemaakt hebt. Het is dus gewoon valide om een waarde van google.com in te geven, waar blijf je dan met je base waarde?

[ Voor 18% gewijzigd door Gomez12 op 07-01-2009 21:43 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Zonder meteen de boodschap uit te willen dragen dat alles maar in een config geknald moet worden: De base url is een typische config optie. Die ene superhandige config eenmalig instellen is bovendien ook nog idioot veel eenvoudiger dan dat nog steeds verre van perfecte geneuzel waar je nu mee bezig bent (lees: ook je huidige idee slaat als een tang op een varken :> ) . :)

[ Voor 9% gewijzigd door Voutloos op 07-01-2009 21:42 ]

{signature}


Acties:
  • 0 Henk 'm!

  • Svennetjee
  • Registratie: December 2007
  • Laatst online: 18:13
Gomez12 schreef op woensdag 07 januari 2009 @ 21:40:
[...]

Waarom in vredesnaam een regex? En helemaal zoals je het hier gemaakt hebt. Het is dus gewoon valide om een waarde van google.com in te geven, waar blijf je dan met je base waarde?
Svennetjee schreef op woensdag 07 januari 2009 @ 21:33:
[...] ik gebruik die dingen niet meer nu. Alleen nog even een check op valide headers.
Ik gebruik die headers niet meer voor de base, of enige andere, waarde, die voer ik gewoon in in een config file. Maar desalniettemin leek het me toch verstandig om even globaal te checken of de url in die variabele valide is..

Acties:
  • 0 Henk 'm!

  • TeeDee
  • Registratie: Februari 2001
  • Laatst online: 21:07

TeeDee

CQB 241

Waarom? Globaal een url checken op validiteit? In deze context lijkt het me niet nuttig EN geeft het jou een vals gevoel van veiligheid. Laat het valideren van deze variabele achterwege en maak je druk om andere zaken :)

Heart..pumps blood.Has nothing to do with emotion! Bored


Acties:
  • 0 Henk 'm!

  • frickY
  • Registratie: Juli 2001
  • Laatst online: 18-09 14:42
Ik zie neit hoe je de SERVER_NAME zou kunnen spoofen :?

De HTTP_HOST is eenvoudig. Dat is gewoon een HTTP/1.1 veld die de cliënt zelf meegeeft. Bij een browser komt deze overeen met de domeinnaam in je adresbalk, maar een andere client kan er neerzetten wat hij wiot.

De SERVER_NAME echter is de naam van de (virtual-)host welke de webserver aan het request heeft toegekent, en komt uit de eigen configuratie. Hoe zou die spoofbaar moeten zijn?
Sterker nog, de van toepassing zijnde (virtual-)-host wordt in HTTP/1.1 herleid uit het HOST-header (bij IP-based hosting, zoals HTTP/1.0, wordt het IP gebruikt). Als de Host gespoofed wordt en je zit op een shared bak, zal de gebruiker ook niet in jouw Document_root tetrecht komen, maar die behorende bij de gespoofde Host, of de globale als er geen matchende Host geconfigureerd is. Jouw script zal dus uberhaupt niet worden uitgevoerd.

Ik zou me eerder druk maken om SQL-injection en XSS dan dit soort fratsen.

Een base-url kun je overigens uitlezen uit de $_SERVER['DOCUMENT_ROOT']
Of ikzelf heb in mijn ./inc/config.php altijd het volgende staan;
PHP:
1
define('DOC_ROOT', realpath(dirname(__FILE__) . '/../')));


Als de 'config.php' staat in /var/www/vhosts/www.example.com/inc/config.php dan bevat de constante DOC_ROOT altijd de waarde /var/www/vhosts/www.example.com

[ Voor 67% gewijzigd door frickY op 08-01-2009 09:32 ]


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Svennetjee schreef op donderdag 08 januari 2009 @ 08:55:
Maar desalniettemin leek het me toch verstandig om even globaal te checken of de url in die variabele valide is..
Totale wereldvrede lijkt mij ook wel verstandig, maar ik probeer het niet voor de lol via mijn script te bereiken als het geen functionele requirement van het sript is. :z

{signature}

Pagina: 1