fbpx

IMVU – En stor 3D-community som antagligen – förhoppningsvis – har haft sin boom för längesen. Den drar, precis som alla andra sidor i sin kategori, till sig en massa skumma människor och är i princip en fantasi-köttmarknad, där man bygger upp förväntningar på varandra i form av små figurer som egentligen inte existerar. Det finns också en vanlig marknad, för försäljning av modegrejer, kläder, grejer, djur, osv som egentligen inte existerar. För mig är dock den här platsen enbart en historisk säkerhetskatastrof. Jag har tidigare skrivit ett inlägg på engelska (http://www.tornevalls.se/blog/2007/10/01/xss-at-imvu-still-unprotected/) angående just säkerheten på sidan, eftersom man tillåter en liten aning för mycket designande på användarnivå. Och när man befinner sig på en webbplats där man tillåter användarna att redigera sin design fullt ut, i html, så kan man också räkna med problem.

Naturligtvis var just ”problem” en term som dök upp tidigt under den period i mitt liv då jag ”lärde känna” communityn. 17 februari 2007 dök en tråd upp i IMVU-forumet, där man påpekade att krediter hade börjat försvinna från olika konton. Detta hände bara några månader efter att jag varnat ett par exvänner, som haft problem med förföljelse, för att använda IMVU ”för mycket” till sina privata grejer, eftersom profilsidorna var extremt sårbara för olika attacker. I mars samma år stängdes möjligheten att använda javascript i användarnas profiler, tillfälligt. Tills ”problemen var åtgärdade” hette det. Saken var nämligen att man med hjälp av javascript kunde stjäla andra användares konton, genom att anropa parametern document.cookie – vilket förmodligen var precis vad som hände.

IMVU löste sitt problem. Fast på ett fånigt bekvämligt sätt, visade det sig. Vad man egentligen gjorde var en ”sök och ersätt” om innehållet ”document.cookie” fanns med på användarnas egendesignade sidor. Problemet är att, så länge all html-kodning fortfarande är möjlig för användaren räcker det med att slänga runt orden lite och nyttja övrig javascript-funktionalitet för att passera ett sådant skydd. Om någon förstått det än är oklart och samtidigt ganska förståeligt, på grund av att variabler i modifierad form vanligtvis är harmlösa. Och säkerheten i javascript är alltså precis vad det här inlägget tar upp.

Någon ”vanlig” XSS-injection är det inte tal om, eftersom säkerheten i alla webläsare har stärkts betydligt. I det här specifika fallet talar jag om AJAX, som gör websidor mer interaktiva; en del sökmotorer använder sig av AJAX idag och innebär kort att när användaren exempelvis skriver in en bokstav i ett sökfält, så returneras alternativa sökord till användaren. Anropen sker, som AJAX antyder, i bakgrunden med hjälp av javascript. Men som jag sade så har säkerheten blivit högre – det går till exempel inte längre att hämta data från andra websidor med AJAX, om inte datat man anropar befinner sig under samma domän som själva huvudanropet. Det går således inte att skicka iväg cookies till en annan server heller, som fångar upp dem. Inte längre i alla fall, men det har fungerat. Vilket jag svurit över några gånger på jobbet, då vi själva nyttjar sådan funktionalitet. Enda lösningen på det är att helt enkelt lägga allt på samma server. AJAX fungerar förvisso fortfarande rätt bra om man ser till att anropa alla funktioner från samma domän, annars det krävs det att användaren själv väljer att sänka säkerheten i sin webbläsare och det lär det inte vara många som gör.

I alla fall – jag nämnde nyss att variabler i omskriven form är effektlösa. Vilken tur!

Nja… Det går ju faktiskt att komma förbi. För att få en textsträng från en variabel att fungera som om det vore ett script kan man evaluera den med eval-funktionen:

var ingredient = 'cook documentie';
var newword = eval(ingredient.substr(5,8) + "." + ingredient.substr(0,4) + ingredient.substr(13,2));

I ovanstående funktion skapas en textvariabel innehållande ”cook documentie”. Det ser väl harmlöst ut, vid första anblicken?

På andra raden i scriptet kastar vi om textsträngen så att den åter bildar ordet ”document.cookie” istället. Skickar man ut det med en alert eller en document.write, så får man alltså på skärmen läsa ”document.cookie” igen, om det inte hade varit för evalueringen av den. En evaluering av textsträngen gör nämligen att den åter körs ”live”. En alert(newword) kommer alltså returnera de cookies som är aktuella för den websida man besöker och därmed de sessionsvariabler som håller användaren inloggad på sidan – vilka, om en webmaster är en dålig programmerare, kan vara okrypterade lösenord. Det har visserligen ingen större betydelse, när man plockar upp cookies så här eftersom man ändå kan komma åt ett konto på det här sättet. För det mesta i alla fall. Nackdelen med okrypterade lösenord i en cookie är just att de är okrypterade och därmed ges en angripare bara större möjligheter att förstöra något.

Problemet med den här typen av script är att få dem att fungera helt utan interaktion från användaren. Eftersom AJAX bara fungerar så länge man inte lämnar samma domän så blir det alltså svårt att dölja anropen och enda sättet att snappa upp cookies är om man ber användaren att klicka på en knapp, som man sedan länkar till en annan websida – eller helt enkelt be användaren skicka dem direkt och spara tid. Det blir dock lite väl uppenbart om man ber användaren att klicka någonstans, eftersom detta lämnar rejäla avtryck i användarens webläsare, om man inte använder webformulär med POST-metoden. Samtidigt, som det faktiskt krävs att användaren gör något. Å andra sidan så är all hänvisning bort till en helt annan plats generellt sett väldigt suspekt. Och även om det går att lura några så går det lyckligtvis inte att lura alla. Mycket källkod i ett dokument innebär också större chans att någon ser vad som sker och det kanske inte är all kod som fungerar, beroende på hur webmastern städar sina användares källkod. Vi vill alltså bara använda det lilla som krävs för att koden skall fungera.

Så, då är det alltså omöjligt att stjäla cookies eftersom säkerheten hindrar webläsarna att lämna domänen – och så länge man inte interagerar med användaren så fungerar det inte.

Jo… Det gör ju det. Och faktum är att man inte behöver be användaren att interagera alls. Det är alltså här någonstans som webansvariga bör fundera på hur mycket kod de egentligen borde tillåta att användarna kör. Ju fler funktioner, desto mer skräp kan passera, så att säga. Egentligen räcker det med att döda eval och document.cookie för att man skall kunna frånta väldigt många sätt att knäcka cookies på. Så det återstående problemet är att dölja anropet och ändå få tag på cookies utan att visa användaren att man vill ha dem. Och utan att först behöva be användaren om dem…

Bilder är bra! När man laddar in en bild så ser användaren bilden och inget annat. Men via bilder kan man inte skicka cookies. Eller? Jo. Tack vare webläsares flexibilitet via javascript, så kan man göra många anrop både här och där i källkoden som man inte ens trodde var möjligt. Exempel? Något som är vanligt, i synnerhet på köttmarknadswebsidor (läs: datingsiter), är att man låter användaren föra muspekaren över en miniatyrbild som föreställer någons fotografi för att öppna en större bild av användaren. Väldigt kortfattat fungerar detta genom att man anropar onmouseover-funktionen och då har interaktion med användaren skapats. Men med onmouseover följer också ett krav på användaren, att de måste göra något, så det blir inte riktigt bra. Men som bekant tillåter javascript väldigt mycket… Exempelvis så finns funktionen onload tillhands om man vill utföra kommandon på en websida, som skall ske när websidan laddas in första gången. En intressant sak som kan vara värt att påpekas är att onload bara fungerar en gång, så en fuskmetod som den nedan kommer alltså inte fungera:

<body onload="alert('1')">
<body onload="alert('2')"></body>
</body>

Men alla websidor som inte själva laddar in något kan man således uppenbarligen lura. Det kan exempelvis se ut så här, vilket fungerar utmärkt:

<body>
<body onload="alert('2')"></body>
</body>

På skärmen, vid laddning av den koden, kommer siffran ”2” dyka upp. Så i kombination med interaktionskommandon, borde det alltså gå att ladda in en bild, med hjälp av onload och samtidigt be bilden att skicka över alla cookies till en websida som inte ligger inom samma domän, även om document.cookie är avstängd? Javisst!

<script>
AnropaEnFunktion()
{
    document.getElementById("BildUtrymme").innerHTML = '<img src="http://server/bild.jpg">';
}
</script>
<body onload="AnropaEnFunktion()"></body>
<div id="BildUtrymme">&nbsp;</div>

I ovanstående funktionsanrop, under förutsättning att huvudsidan inte redan har en body onload, har vi gjort det möjligt att ersätta innehållet i ett element med en bild, helt automatiskt. Anropet blir naturligtvis effektlöst om webläsaren inte har javscriptfunktioner aktiva, men så vitt jag vet så levereras alla vanliga webläsare med denna funktionalitet öppen. Man kan förstås, till exempel i Firefox, skaffa sig NoScript-tillägget, men stänger man av javascript så stängs också alla andra funktioner på hemsidan man besöker av. Eftersom javascript är vida använt idag riskerar man därmed, om man tar IMVU som exempel, att stänga av saker som behövs för att sidan skall fungera överhuvudtaget. Om ovanstående kod skrivs om, bara en liten aning, kan man alltså på samma sätt även börja skicka parametrar till en annan server. Denna annorlunda funktionalitet gör att vi kan passera alla tidigare vanliga säkerhetsspärrar, eftersom vi inte ber javascriptet att exekvera något som ligger på en annan server. Vad som egentligen sker är att vi ber javascriptet göra ändringar på den sida vi redan befinner oss på. Således kommer hela idén med att skydda webbläsare mot ”dålig” Cross Site Scripting (XSS) vara överflödig, med teknisk knockout på första slaget.

Så, ett hett tips till alla webprogrammerare där ute, som vill ge sina användare hög tillgänglighet på sin design i community-profiler är: Don’t do it!

av Tornevall

Fotograf, musiker, filmare. Estetikens alla nyanser i ett, kombinerat med humor och ett förflutet inom vård- nöjes- och programmeringsbranscher.