PHP is een krachtige taal en de interpreter, zowel als module in een webserver, of uitgevoerd in een afzonderlijke CGI binary, kan bestanden lezen, commando's uitvoeren en netwerk connecties openen op de server. Deze eigenschappen maken alles wat draait op een webserver onveilig als default. PHP is ontworpen als een veiliger taal om CGI programma's te maken dan Perl of C, en met de juiste selectie van compile-time en runtime configuratie opties, en een goede coding stijl, kan het je over de exacte combinatie van vrijheid en veiligheid beschikken die jij nodig hebt.
Omdat er veel verschillende manieren zijn om PHP te gebruiken, zijn er ook veel opties die het gedrag aanpassen. Een grote keus aan opties garanderen dat PHP gebruikt kan worden voor veel doeleinden, maar het betekend ook dat er combinaties zijn van opties en server configuraties die resulteren in een slecht beveiligde setup.
De configureerbaarheid van PHP is evenredig met de felixibiliteit van code schrijven. PHP kan gebruikt worden om complete server applicaties te schrijven met de kracht van een shell user, maar ook voor simpele server-side includes met weinig risico en een goed te controleren omgeving. Hoe zo'n omgeving te creeren en hoe veilig het is, hangt grotendeels af van de PHP ontwikkelaar.
Dit hoofdstuk start met het uitleggen van de verschillende combinaties van opties en de situaties waarin deze veilig kunnen worden gebruikt. Hierna zal het verschillende mates van beveiliging van de geprogrammeerde scripts doornemen, en het zal eindigen met een algemeen beveiligins advies.
PHP gebruiken als CGI binary is een optie voor personen die om een of andere reden PHP niet willen integreren als een module in server software (zoals Apache), of die PHP met verschillende CGI wrappers willen gebruiken om zo een veilige omgeving voor scripts te creën. Deze opzet vereist vaak het installeren van de PHP binary in de web server's cgi-bin directory. CERT advisory CA-96.11 beveelt of om interpreters in de cgi-bin te installeren. Zelfs als een binary gebruikt wordt als een standalone interpreter is PHP ontworpen om een aantal aanvallen op deze setup te verijdelen:
Het lezen van systeem bestanden: http://mijn.server/cgi-bin/php?/etc/passwd
De string in een URL na het vraagteken (?) wordt doorgegeven als argumenten aan de interpreter door de CGI interface. Gewoonlijk openen interpreters het eerste argument als het script dat ze proberen uit te voeren.
Als PHP als CGI binary word gebruikt, dan vertikt hij het om command line argumenten te accepteren.
Het lezen van elk web document op de server: http://mijn.server/cgi-bin/php/geheim/doc.html
De bestandslocatie in de URL achter de PHP binary naam, /geheim/doc.html wordt normaal gebruikt om de naam van het uit te voeren bestand aan te geven dat moet worden uitgevoerd door het CGI programma. Normaal gezien wordt een configuratie optie (Apache: Action) gebruikt om zulke requests als http://my.host/secret/script.php3/secret door te sturen naar de PHP interpreter. Op deze manier worden eerst de toegangsrechten naar de directory /secret gecontroleerd. Pas daarna wordt het nieuwe request http://my.host/cgi-bin/php/secret/script.php3 uitgevoerd. Helaas worden requests welke in deze vorm gegeven worden niet gecontroleerd op toegangspermissies. Er word alleen gekeken of er toegang is tot /cgi-bin/php en niet of er toegang is tot /secret/script.php3. Op deze manier kan elke gebruiker met toegang tot /cgi-bin/php elk beschermd document in de web tree benaderen.
In PHP, de compile-time configuratie optie --enable-force-cgi-redirect en de runtime configuration opties doc_root en user_dir kunnen worden gebruikt om dit type aanval, als de web document tree enige directories heeft met restricties. Zie hier onder voor een volledige uitleg van alle verschillende combinaties.
Als jouw server geen enkele beveiligde webpagina heeft, bijvoorbeeld met een wachtwoord, of gebaseerd op IP, dan is het niet nodig om deze configuratie opties te gebruiken. Indien jouw webserver het niet toestaat om redirects te doen, of de server kan op geen enkele manier communiceren met de PHP binary dat de informatie aanvraag is een veilig geredirectioneerde aanvraag dan kun je de optie --enable-force-cgi-redirect veilig toevoegen aan de configure regel. Je zult wel zelf moeten controleren of jouw PHP scripts niet afhankelijk van elkaar zijn bij het direct aanroepen http://mijn.server/cgi-bin/php/dir/script.php3 en via redirectie http://mijn.server/dir/script.php3.
Redirectie kan in Apache worden geconfigureerd met behulp van AddHandler en Action regels (zie hieronder).
Deze compile-time optie voorkomt het direct aanroepen van PHP met een URL als volgende http://my.host/cgi-bin/php/geheimedir/script.php3. In plaatse hiervan zal PHP het scripts alleen parsen in deze mode als het via een web server's redirect rule wordt aangeboden.
Normaal gesproken is redirectie in Apache te configureren met de volgende directives:
Action php3-script /cgi-bin/php AddHandler php3-script .php3 |
Deze opties is alleen getest met de Apache web server, en gaat ervan uit dat Apache de niet standaard CGI environment variable REDIRECT_STATUS gebruikt bij redirectioneerde aanvragen. Als jouw web server geen manier heeft om door te geven of een aanvraag is geredirectioneerd of niet, dan kun je deze optie niet gebruiken en zal je een andere manier moeten vinden om de CGI versie te runnen.
Soms wordt in twijfel getrokken of het gebruiken van scrips of programma's in de web server document directories wel veilig is. Als namelijk, vanwege een configuratie foutje, de scripts niet worden uitgevoerd, maar worden getoond als normale HTML documenten, dan kan er copyrighted materiaal, of beveiliginsinformatie als wachtwoorden beschikbaar komen voor onbevoegden. Hierom zullen veel beheerders een apparte directory opzetten die altijd wordt uitgevoerd door de PHP CGI, hierdoor komt de source van de PHP scripts nooit beschikbaar komen voor onbevoegden.
Als er geen manier is om te controleren of een aanvraag is niet doorverwezen, zoals bescrijven is in de vorige Case, dan is het ook nodig om een doc_root op te zetten die verschillend is van de web documenten root-directory.
Je kunt de document van een PHP script instellen met de configuratie directive doc_root in de configuratie file, of met het setten van de environment variabele PHP_DOCUMENT_ROOT. Als deze is ge-zet dan zal de CGI versie van PHP altijd de bestandsnaam gebruiken met de doc_root en path informatie van de aanvraag. Op deze manier is het zeker dat geen script wordt uitgevoerd buiten de directory (met uitzondering voor user_dir die hieronder wordt beschreven).
Een andere bruikbare optie is de user_dir. Als user_dir niet getset is, dan is het enige dat de geopende file beïnvloed de doc_root. Het openen van een URL als http://mijn.server/~gebruiker/doc.php3 resulteerd niet in het openen van een bestand in de home directory van de gebruiker, maar van het openen van ~gebruiker/doc.php3 in de doc_root (een directory die met een tilde begint [~]).
Als user_dir de waarde public_php is, een aanvraag als http://mijn.server/~gebruiker/doc.php3 zal de file doc.php3 in de directory genaamd public_php openen in de home directory van de gebruiker. Als de home directory van de gebruiker /home/gebruiker is, dan zal het uitgevoerde bestand /home/gebruiker/public_php/doc.php3 zijn.
user_dir expansie gebeurd onafkanelijk van de waarde van doc_root. Dit maakt het mogelijk om de document root en user directory toegang afzonderlijk te configureren.
Een erg veilige optie is het plaatsen van de PHP binary buiten de directory met web bestanden. De PHP binary wordt voor deze methode vaak in /usr/local/bin geplaatst. Het enige nadeel is hieraan dat je nu een regel moet toevoegen aan een script. Deze regel moet de eerste zijn in een script en ziet er als volgt uit:
Het is ook noodzakelijk dat het script uitvoerbaar wordt gemaakt. Dit impliceerd dat je het script moet zien als elk ander script dat gebruikt wordt in CGI, zoals in Perl, shellscript of elke andere taal die het #! shell-escape mechanisme gebruikt voor het starten van zichzelf.Om er voor te zorgen dat PHP PATH_INFO en PATH_TRANSLATED information correct gebruikt in deze setup, moet de PHP parser worden gecompileerd met de --enable-discard-path configure optie.