+------ | Oppdatering 2004-01-05: Du kan lese _mye_ mer i min nylig utgitte | bok: "Innocent Code: A Security Wake-up Call for Web Programmers" | http://innocentcode.thathost.com/ +------ Client Side Trojans, eller: Hvordan stjele penger ved å sende en mail ===================================================================== Sverre H. Huseby shh@heimdall.no 2002-06-20 Hei, kjære webutviklerkollega. Vil forsøke å minne om at sikkerhet i en webløsning er langt mer enn en god brannmur og 128 bits kryptering. Det er opp til oss også. Vi gjør så lett feil når vi programmerer. Og grunnen til at vi gjør feil er at vi ikke er opplært til å tenke destruktivt. Vi jobber iherdig for at kundene våre skal få den funksjonaliteten de ønsker, men glemmer lett at løsningen vår også er tilgjengelig for en haug med folk som kunne tenke seg å misbruke den. I mai 2000, etter at World Wide Web hadde eksistert i omtrent 10 år, var det noen som satt fingeren på et temmelig skummelt problem. Undertegnede fant problemet så hårreisende at han faktisk vurderte å slutte med utvikling av webløsninger. Weben kunne bare ikke bli sikker. Trodde jeg. Helt til en av mine eks-kolleger (hei, Filip!) skisserte en løsning. Det dreier seg om en angrepstype som utviklerne av applikasjons- tjeneren Zope kalte "Client-side Trojans" (CST), en temmelig intet- sigende og en smule forvirrende betegnelse. Problemet vises lettest med eksempler. Før vi kommer til banker og slikt (jada, det virker mot nettbanker også), starter vi med det enkle. Tenk deg en webløsning som lar brukere stemme om et eller annet ved å velge blant flere alternativer. Du finner denne typen funksjonalitet nær sagt over alt. En stemme-webside vil kunne inneholde HTML som ser omtrent slik ut:
Alternative 1
Alternative 2
:
Siden formen bruker GET, vil browsere besøke URLer som ser slik ut når brukerne gir sin stemme: http://www.example.com/vote.asp?alt=2 Sett nå at jeg, av en eller annen grunn, gjerne vil at mange mennesker skal gi sin stemme til nettopp alternativ 2. Hva hindrer meg fra å sende mail hit og dit med oppfordring om å besøke den ovenfornevnte URLen med løfte om en morsom vits, et artig spill, nakne damer, eller hva det nå måtte være som lurer folk til å følge linken? Ingen ting! Og jeg kan med letthet lure en rekke mennesker til å stemme slik jeg vil, uten at de er klar over det selv. Aha! sier du kanskje. Ingen følger den linken, for den ser så mis- tenkelig ut. Men en angriper lurer med letthet de som sjekker linker også. Han lager bare en egen side, og henviser til den: http://www.badguy.com/nicejoke.html nicejoke.html inneholder selvsagt ikke en morsom vits, den inneholder HTML som ser slik ut: eller kanskje et script: Begge metodene (eller bruk av Location-header for de litt mer avan- serte) vil få browseren til umiddelbart å forflytte seg til den mis- tenkelige URLen, uten at brukeren har noen mulighet for å stoppe overgangen. Greit nok. Men nå er det engang slik at man gjerne skal bruke POST, og ikke GET, når man gjør operasjoner som fører til et eller annet. I hvert fall hvis man skal følge RFC 2616 som beskriver HTTP. Og med POST kan man vanligvis ikke sende noen en URL som inneholder para- metre. No problemo, for å sitere en kjent robot. Istedenfor å lure brukeren til å besøke en URL, lurer angriperen dem til en side som inneholder en ferdig utfylt form med någo attåt:
Formen, som likner mistenkelig på den opprinnelige stemme-formen, har fått det velklingende navnet "f". Og den har et HIDDEN-felt hvor angriperens ønskede valg allerede er fylt ut. Magien ligger i det lille scriptet som befinner seg rett under formen. Scriptet sender formen akkurat som om brukeren hadde trykket en submit-knapp. Og sendingen skjer automatisk idet browseren viser den slemme websiden. Før ofrene vet ordet av det har de avgitt sin stemme. En litt mer fancy framgangsmåte består i å legge formen og scriptet i en HTML-kodet mail. Flere populære mailprogrammer viser HTML-mail uten problemer, inkludert kjøring av scripts. Uheldige brukere kan således lures til å avgi sin (eller rettere: angriperens) stemme ved kun å lese en mail. (For spesielt interesserte: Microsoft Outlook bruker en MSIE-kompo- nent for å vise HTML-mail. Jeg testet litt mot nettbanken min (hei, Økokrim!) og fant ut at Outlook sin MSIE-komponent deler alt med en evt. åpen Internet Explorer, inkludert sesjons-cookies. Ha det i bakhodet når vi nå kommer til banker og autentisering.) Så langt har vi sett på en tullete avstemningsapplikasjon. (Tullete og tullete, fru Blom: det er ikke lenge siden en tysker postet en mengde avstemnings-CSTer til diverse nyhetsgrupper for å lure folk til å stemme over hvem (i klassen hans?) som skulle få reise til USA.) Men det som virkelig er skremmende med Client-side Trojans, er at de også virker med autentisering: Siden triksingen skjer ved å lure bruk- erens browser til å utføre et eller annet, kan man også nå steder hvor brukeren er autentisert. Sett at brukeren er logget inn på nettbanken sin. Hvis en ekling ønsker å fralure stakkaren litt penger, kan det tenkes at det er nok å lure offeret til å se følgende HTML i browseren sin:
Hvis offeret allerede er logget inn (og banken godtar forms av typen angitt over (jada, det finnes utrolig nok norske nettbanker som lar seg lure så lett)), vil han nå, uten å ville det, overføre penger. Problemet med CSTer mot login-baserte nettsteder, er at man må for- sikre seg om at brukeren er logget inn før man kan sende lureriet sitt til dem. Og i mange tilfeller er offeret logget inn til enhver tid. Bare tenk på alle "remember me"-opsjonene som finnes rundt omkring. Eller på NTLM-autentiseringen som brukes i mange intranett. I slike tilfeller vil browseren og serveren automatisk logge brukeren inn. I mer "alvorlige" webløsninger, som i nettbanker og slikt, kan man vanskelig vite når brukeren er logget inn. Derfor er det langt mer vrient å sende brukeren en CST på riktig tidspunkt. Inntrengeren vil derfor kunne ty til sin venn i nøden, nemlig "Social Engineering". Eller "Sosial ingeniørkunst", som Dagbladet kaller det. Social Engineering går rett og slett ut på å lure godtroende mennesker, hvilket gjerne vil si de fleste av oss. Sett at målet er en kunde av banken bank.example.com. Inntrengeren kan feks. forfalske avsender, og sende en mail som ser slik ut: To: offeret From: security@bank.example.com Subject: Viktig melding fra din nettbank! Kjære Ola Nordmann På grunn av hendelser nylig, ber vi deg hjelpe oss med å verifisere at din konto er korrekt. Vennligst logg inn på nettbanken, og gå til: http://bank.example.com@167772161/check.html Med vennlig hilsen, Kari Nordmann, sikkerhetssjef i Example Bank. Folk flest vil tro at URLen peker til bank.example.com. Men det gjør den ikke. På grunn av @-tegnet sier denne URLen at browseren skal gå til 167772161, og identifisere seg som brukeren bank.example.com. Det merkelige tallet er IP-adressen 10.0.0.1 kodet om til et 32-bits hel- tall. 10.0.0.1 er selvsagt angriperens maskin, og check.html er en webside som inneholder en selvpostende form. Voila! Inntrengeren er X kroner rikere. De fleste vil bli mistenksomme når de ser en webside som viser at de nettopp har overført penger. Men denne websiden kan lett gjemmes, feks. ved kreativ bruk av frames. Jeg håper du nå har innsett at Client-side Trojans kan være et stort problem i en rekke webløsninger. Er det noe vi som webutviklere kan gjøre for å unngå problemet? Som det framgår av teksten, er CST et problem som kan initieres utenfor vår webløsning. Inntrengeren kan sende mail med scripts, eller henvise offeret til websider som ikke på noen måte er knyttet til løsningen vi lager. Fra mailen eller websiden lures så offerets browser inn i vår webapplikasjon. Vi kan gjøre så mye input-filtrering vi vil, og så mye HTML-koding av output vi klarer. Allikevel er løsningen vår mottakelig for Client-side Trojans. En løsning på problemet kan være å kreve en slags re-autentisering hver gang brukeren ønsker å utføre noe. Vil du overføre penger? Ja vel, vennligst tast inn passordet ditt en gang til. Eller finn fram kodekalkulatoren, tast inn passordet på den, og tast så tallet i displayet inn i dette feltet. Re-autentisering vil kunne løse problemet, men det er langt fra brukervennlig. Vi vil helst ikke bry brukeren mer enn nødvendig. For å kunne finne en transparent løsning, må vi forstå hva som er det egentlige problemet. Og det er faktisk ganske enkelt: Client-side Trojans virker fordi noen gir en bruker et tilbud på vegne av vår web- løsning. Noen oppfordrer brukeren, eller brukerens browser, til å besøke vårt websted med ferdig utfylte parametre. Hvis vi klarer å skille mellom handlinger som baserer seg på våre til- bud, og handlinger som baserer seg på eksterne tilbud, er vi egentlig i havn. (For spesielt interesserte igjen: Jo'a, Referer-header kan kanskje brukes i akkurat dette tilfellet, men mange filtrerer den bort.) Og det er her min gamle eks-kollega (hei igjen, Filip!) kom med en god ide som jeg etter hvert har valgt å kalle "billetter". En forenklet versjon av billettsystemet går omtrent som følger: Hver gang vi gir brukeren et tilbud med sideeffekter, hvilket bør håndteres av en form med POST, hoster vi opp et stort, ikke-gjettbart tall. Dette tallet er billetten. Vi knytter billetten til tilbudet via et hidden-felt i formen. Og samtidig lagrer vi en kopi av tallet på serversiden, i brukerens sesjon. Når brukeren følger tilbudet vårt ved å poste formen, får vi brukerens kopi av billetten i retur. Vi sjekker så om en tilsvarende billett finnes i sesjonen. Finner vi en, vet vi at tilbudet brukeren følger er et tilbud vi opprinnelig ga, og ikke et som kommer fra utsiden. Et tilbud fra utsiden vil ikke kunne inneholde en gyldig billett. Jada. En del mer arbeid for oss stakkars programmerere. Men er vi ekstra flinke, lager vi et rammeverk som automatisk genererer og sjek- ker billetter for oss. Og er vi er superflinke, klarer vi kanskje også å lage et rammeverk som inkluderer automatisk inputvalidering, vasking av metategn, HTML-filtrering og det meste annet som vi programmerere gjerne glemmer å tenke på, takket være vår mangelfulle utdannelse. Og der var jeg tilbake til utdannelsen igjen. Landet vårt (og verden forøvrig) er fult av utviklere som i løpet av sin lange universitets- eller høyskoleutdannelse aldri har blitt oppfordret til å ofre en tanke på sikkerhet. På 70- og 80-tallet var det kanskje greit nok, da lagde vi programmer som snurret og gikk på en maskin innenfor organisasjonens trygge vegger. I våre dager er imidlertid veggene borte. Og det er vel på tide at vi kanskje begynner å ta hensyn til det. Eller hva? * Den originale Zope-diskusjonen om Client-side Trojans http://www.zope.org/Members/jim/ZopeSecurity/ClientSideTrojan * RFC 2616, "Hypertext Transfer Protocol -- HTTP/1.1" http://www.ietf.org/rfc/rfc2616.txt * Mer skriverier av undertegnede http://heimdall.no/tekst.html * Sverres kontaktinformasjon shh@heimdall.no, http://heimdall.no/ ---------------------------------------------------------------------- En sønderklippet utgave ble publisert i Computerworld nr. 49, august 2002