Riktig beskyttelse mot Cross Site Scripting- og SQL-injection-angrep

De siste årene har vi sett flere massive SQL-injection- og Cross Site Scripting (XSS)-angrep mot store siter. Twitter hadde nylig en XSS-feil og i begynnelsen av juni var det et stort angrep mot siter som kjørte en bestemt annonsekomponent. Beskyttelse mot denne type angrep, krever at man tenker på kontekst når man skriver kode.

Validering av input er ikke løsningen
Tidligere snakket man ofte om at manglende validering av input var årsaken til disse feilene. Dette er dessverre ikke riktig. Validering av input handler om å sjekke at input er riktig i forhold til domenet. Dette vil riktignok stoppe mange angrep, men på langt nær alle. Et godt eksempel er navnet “Ken-Martin O’Conner”. Dette etternavnet inneholder flere tegn som også er kontrolltegn i SQL. For å kunne godta dette navnet må man ved validering av input godta både bindestrek og fnutter. Dermed vil man også tillate et angrep som ' OR '' LIKE '' --. Man kan selvsagt forsøke å gjøre valideringen enda strengere, men man risikerer kjapt å avvise gyldig input.

Jeg sier ikke at validering av input er unødvendig – det er bare ikke løsningen på dette problemet.

Kontekst og escaping
Problemet ved både XSS- og SQL-injection-feil er at data flyter fra en kontekst og over i en annen. Ved overgang fra f.eks. javakode til SQL, må vi sørge for at vi beholder semantikken. Skal vi sette inn en datastreng i en SQL-spørring, må vi sørge for at det forblir en streng. Dette gjør vi ved å foreta output escaping. For SQL er løsningen enkelt og greit å ta i bruk parameteriserte spørringer (prepared statements). Bruker vi prepared statements og gir inn parametrene i etterkant, vil rammeverket håndtere escaping av kontrolltegn for oss.

For XSS er det desverre noe vanskeligere. Når data forlater vår applikasjon og går over til noe browseren skal tolke, er det nemlig flere mulige kontekster. Vi kan skrive ut innhold i javascript, javascript i HTML, mellom HTML-tagger, i HTML-attributter osv. Og flere av disse kontekstene må behandles forskjellig. Vi kan begynne med input som skrives ut mellom HTML-tagger. Dette er den enkleste konteksten. Vi kan bruke dette eksempelet:

<div>Du søkte på "her kommer inputten"</div>

For å hindre kjøring av script her, må vi sørge for at input ikke kan åpne nye tagger, f.eks. en <script>-tag. Dette gjør vi selvsagt da ved å erstatte > med &gt; og < med &lt;.

I HTML-attributter, må vi også passe oss for enkle eller doble fnutter alt etter hva som er brukt. Et eksempel på denne konteksten kan være:

<input type="text" value="her kommer inputten"  name="searchValue" />

Et typisk angrep ville i dette tilfellet ha brutt ut av value-attributtet og åpnet en javascript-event (f.eks. onclick eller onmouseover). Her må vi altså " med &quote; og ' med &#x27; eller &#39;. Men i noen tilfeller glemmer utviklere å bruke fnutter til å avgrense attributtverdier, så til og med et mellomrom kan lede til problemer.

Ser vi på javascript i HTML, kan det se slik ut:

...
<body>
<script>
var searchTerms = 'her kommer inputten';
</script><code>
...
</body>
...

Her er det kanskje lett å tenke at det holder å legge til en backslash forann eventuelle enkle fnutter (' blir til \'), men vi må huske at vi er i en såkalt dobbel-kontekst: Javascript-kontekst inni en HTML-kontekst. Vi må derfor også passe oss for HTML-tegn. Her er et eksempel på hvorfor man må escape for begge kontekster.

For mer informasjon om de forskjellige XSS-kontekstene, se OWASP XSS Prevention Cheat Sheet.

For .NET finnes det et bibliotek kalt Web Protection Library. Dette biblioteket har en komponent som heter AntiXSS, som kan escape for forskjellige kontekster. For Java kan man f.eks. benytte encoderen i ESAPI.

Oppsummert
Beskyttelese mot disse angrepene må gjøres med kontekstbasert escaping idet vi bytter fra en kontekst til en annen.

  • http://dvikan.no Dag

    Bra tekst!

    Jeg tror sikkerhet og personvern kommer til å bli viktig i årene fremover. XSS bugs ser ut til å være tilstedeværende på veldig mange norske nettsteder. Og beskyttelse mot CSRF er ikke-eksisterende. Jeremiah Grossman omtalte CSRF som en “sleeping giant” i 2006, og den sover nok enda. Hva skjer når den våkner? http://jeremiahgrossman.blogspot.com/2006/09/csrf-sleeping-giant.html Og hvor mange sql injection hull ligger å støver ned?

    For å kunne forhindre ondsinnede hackere å gjøre ugang må man kunne tenke som en ondsinnet hacker. Derfor er det viktig å være åpen om hvordan de gjør det; kun slik kan ordet spres. Og målet må være at til og med hobbyprogrammere har sikkerhet i tankene når de lager sine program.

    Fortsett og skriv, det skal jeg gjøre :)

  • http://memento.myopenid.com/ Erlend Oftedal

    He Dag. Takk for kommentaren. CSRF er nok fremdeles en søvnig kjempe, men heldigvis begynner mange rammeverk å tilby beskyttelse mot dette. RubyOnRails har .feks. XSRF-killer, og det finnes ferdige komponenter både for .NET og Java, men disse er det nok ferre som benytter foreløpig.