SQL-injektion og XSS: hvad hackere af hvid hat ved om at stole på brugerinput

Softwareudviklere har meget i tankerne. Der er utallige spørgsmål at stille, når det kommer til oprettelse af et websted eller en applikation: Hvilke teknologier vil vi bruge? Hvordan skal arkitekturen indstilles? Hvilke funktioner har vi brug for? Hvordan vil brugergrænsefladen se ud?

Især på et softwaremarked, hvor forsendelse af nye apps virker mere som et løb om omdømme end en velovervejet proces, falder et af de vigtigste spørgsmål ofte til bunden af ​​kolonnen "Haster": Hvordan vil vores produkt blive sikret?

Hvis du bruger en robust open source-ramme til at opbygge dit produkt (og hvis en er anvendelig og tilgængelig, hvorfor ville du ikke?), Kan nogle grundlæggende sikkerhedsproblemer, såsom CSRF-tokens og adgangskodekryptering, muligvis allerede håndteres for du.

Stadig vil hurtig bevægende udviklere være godt tjent med at udnytte deres viden om almindelige trusler og faldgruber, hvis kun for at undgå nogle pinlige rookie-fejl. Normalt er det svageste punkt i sikkerheden af ​​din software dig.

Jeg er for nylig blevet mere interesseret i informationssikkerhed generelt og især i praksis med etisk hacking. En etisk hacker, undertiden kaldet en "hvid hat" -hacker, og nogle gange bare en "hacker", er en person, der søger efter mulige sikkerhedssårbarheder og ansvarligt (privat) rapporterer dem til projektejere.

I modsætning hertil er en ondsindet eller "sort hat" -hacker, også kaldet en "krakker", en person, der udnytter disse sårbarheder til underholdning eller personlig gevinst.

Både hvid hat og sort hat hackere bruger muligvis de samme værktøjer og ressourcer og prøver generelt at komme ind på steder, som de ikke skulle være. Men hvide hatte gør dette med tilladelse og med den hensigt at befæste forsvar i stedet for at ødelægge dem. Sorte hatte er de onde.

Når det kommer til at lære at finde sikkerhedssårbarheder, bør det ikke komme som nogen overraskelse, at jeg har fortæret de oplysninger, jeg kan få fat i. Dette indlæg er en destillation af nogle nøgleområder, der er særligt nyttige for udviklere, når de håndterer brugerinput. Disse lektioner er samlet fra disse fremragende ressourcer:

  • Vejledningerne til Open Web Application Security Project
  • Hacker101-spillelisten fra HackerOnes YouTube-kanal
  • Webhacking 101 af Peter Yaworski
  • Brute Logics blog
  • Computerphile YouTube-kanalen
  • Videoer med Jason Haddix (@jhaddix) og Tom Hudson (@tomnomnom) (to dygtige etiske hackere med forskellige, men begge effektive, metoder)

Du er måske bekendt med slagordet, "rens dine input!" Men som jeg håber, dette indlæg viser, er det ikke helt så ligetil at udvikle en applikation med robust sikkerhed.

Jeg foreslår en alternativ sætning: vær opmærksom på dine input. Lad os uddybe ved at undersøge de mest almindelige angreb, der udnytter sårbarheder i dette område: SQL-injektion og cross-site scripting.

SQL-injektionsangreb

Hvis du endnu ikke er fortrolig med SQL (Structured Query Language) -indsprøjtningsangreb eller SQLi, her er en fantastisk forklaringslignende-jeg-fem-video om SQLi. Du kender muligvis allerede til dette angreb fra xkcds Little Bobby Tables.

I det væsentlige kan ondsindede aktører muligvis sende SQL-kommandoer, der påvirker din applikation gennem noget input på dit websted, som et søgefelt, der trækker resultater fra din database. Websteder kodet i PHP kan være særligt modtagelige for disse, og et vellykket SQL-angreb kan være ødelæggende for software, der er afhængig af en database (som i, din Brugertabel er nu en pot med petunier).

En skærm med en SQL Select-kommando, der får hele din base

Du kan teste dit eget websted for at se, om du er modtagelig for denne form for angreb. (Test kun websteder, du ejer, da kørsel af SQL-injektioner, hvor du ikke har tilladelse til at gøre det, muligvis er ulovligt i din lokalitet; og bestemt, universelt, ikke særlig sjovt.) Følgende nyttelast kan bruges til at testindgange:

  • ' OR 1='1 evalueres til en konstant sand, og når den er vellykket, returnerer alle rækker i tabellen.
  • ' AND 0='1 evalueres til en konstant falsk, og når den er vellykket, returnerer ingen rækker.

Denne video demonstrerer ovenstående tests og gør et godt stykke arbejde med at vise, hvor effektivt et SQL-injektionsangreb kan være.

Heldigvis er der måder at afbøde SQL-injektionsangreb, og de koger alle sammen til et grundlæggende koncept: stol ikke på brugerinput.

Afbødning af SQL-injektion

For effektivt at afbøde SQL-injektioner skal udviklere forhindre brugere i at kunne sende rå SQL-kommandoer til nogen del af webstedet.

Nogle rammer vil gøre det meste af det tunge løft for dig. For eksempel implementerer Django begrebet Object-Relational Mapping eller ORM med sin brug af QuerySets. Vi kan tænke på disse som indpakningsfunktioner, der hjælper din applikation med at forespørge databasen ved hjælp af foruddefinerede metoder, der undgår brug af rå SQL.

At være i stand til at bruge en ramme er dog aldrig en garanti. Når vi beskæftiger os direkte med en database, er der andre metoder, vi kan bruge til sikkert at abstrahere vores SQL-forespørgsler fra brugerinput, selvom de varierer i effektivitet. Disse er efter rækkefølge efter mest til mindst foretrukne og med links til relevante eksempler:

  1. Forberedte udsagn med variabel binding (eller parametriserede forespørgsler),
  2. Lagrede procedurer og
  3. Hvidliste eller undslippe brugerinput.

Hvis du vil implementere ovenstående teknikker, er de sammenkædede cheatsheets et godt udgangspunkt for at grave dybere. Det er tilstrækkeligt at sige, at brugen af ​​disse teknikker til at indhente data i stedet for at bruge rå SQL-forespørgsler hjælper med at minimere chancerne for, at SQL bliver behandlet af en hvilken som helst del af din applikation, der tager input fra brugerne og dermed mindsker SQL-injektionsangreb.

Slaget er dog kun halvt vundet ...

Cross Site Scripting (XSS) angreb

Hvis du er en ondsindet koder, er JavaScript stort set din bedste ven. De rigtige kommandoer gør alt, hvad en legitim bruger kan gøre (og endda nogle ting, som de ikke skal være i stand til) på en webside, undertiden uden interaktion fra en faktisk brugers side.

Cross Site Scripting-angreb eller XSS opstår, når JavaScript-kode indsprøjtes på en webside og ændrer sidens adfærd. Dens virkninger kan variere fra ulykkelige gener forekomster til mere alvorlige omgåelser af autentificering eller stjæling af legitimationsoplysninger. Denne hændelsesrapport fra Apache i 2010 er et godt eksempel på, hvordan XSS kan lænkes i et større angreb for at overtage konti og maskiner.

En HTML-dansefest med lidt JS-indskæring

XSS kan forekomme på serveren eller på klientsiden og findes generelt i tre varianter: DOM (Document Object Model) baseret, lagret og reflekteret XSS. Forskellene svarer til, hvor angrebsnyttelasten injiceres i applikationen.

DOM-baseret XSS

DOM-baseret XSS opstår, når en JavaScript-nyttelast påvirker strukturen, adfærden eller indholdet på den webside, som brugeren har indlæst i deres browser. Disse udføres oftest via modificerede webadresser, f.eks. Ved phishing.

To see how easy it would be for injected JavaScript to manipulate a page, we can create a working example with an HTML web page. Try creating a file on your local system called xss-test.html (or whatever you like) with the following HTML and JavaScript code:

  My XSS Example   

Hello there!

var name = new URLSearchParams(document.location.search).get('name'); if (name !== 'null') { document.getElementById('greeting').innerHTML = 'Hello ' + name + '!'; }

This web page will display the title “Hello there!” unless it receives a URL parameter from a query string with a value for name. To see the script work, open the page in a browser with an appended URL parameter, like so:

file:///path/to/file/xss-test.html?name=Victoria

Fun, right? Our insecure (in the safety sense, not the emotional one) page takes the URL parameter value for name and displays it in the DOM. The page is expecting the value to be a nice friendly string, but what if we change it to something else? Since the page is owned by us and only exists on our local system, we can test it all we like. What happens if we change the name parameter to, say, ?

Et screenshot af eksemplet på XSS-siden

This is just one example, largely based on one from Brute’s post, that demonstrates how an XSS attack could be executed. Funny pop-up alerts may be amusing, but JavaScript can do a lot of harm, including helping malicious attackers steal passwords and personal information.

Stored and reflected XSS

Stored XSS occurs when the attack payload is stored on the server, such as in a database. The attack affects a victim whenever that stored data is retrieved and rendered in the browser. For example, instead of using a URL query string, an attacker might update their profile page on a social site to include a hidden script in, say, their “About Me” section. The script, improperly stored on the site’s server, would successfully execute at a later time when another user views the attacker’s profile.

One of the most famous examples of this is the Samy worm that all but took over MySpace in 2005. It propogated by sending HTTP requests that replicated it onto a victim’s profile page whenever an infected profile was viewed. Within just 20 hours, it had spread to over a million users.

Reflected XSS similarly occurs when the injected payload travels to the server, however, the malicious code does not end up stored in a database. It is instead immediately returned to the browser by the web application.

An attack like this might be executed by luring the victim to click a malicious link that sends a request to the vulnerable website’s server. The server would then send a response to the attacker as well as the victim, which may result in the attacker being able to obtain passwords, or perpetrate actions that appear to originate from the victim.

XSS attack mitigation

In all of these cases, XSS attacks can be mitigated with two key strategies: validating form fields, and avoiding the direct injection of user input on the web page.

Validating form fields

Frameworks can again help us out when it comes to making sure that user-submitted forms are on the up-and-up. One example is Django’s built-in Field classes, which provide fields that validate to some commonly used types and also specify sane defaults. Django’s EmailField, for instance, uses a set of rules to determine if the input provided is a valid email. If the submitted string has characters in it that are not typically present in email addresses, or if it doesn’t imitate the common format of an email address, then Django won’t consider the field valid and the form will not be submitted.

If relying on a framework isn’t an option, we can implement our own input validation. This can be accomplished with a few different techniques, including type conversion, for example, ensuring that a number is of type int(); checking minimum and maximum range values for numbers and lengths for strings; using a pre-defined array of choices that avoids arbitrary input, for example, months of the year; and checking data against strict regular expressions.

Thankfully, we needn’t start from scratch. Open source resources are available to help, such as the OWASP Validation Regex Repository, which provides patterns to match against for some common forms of data. Many programming languages offer validation libraries specific to their syntax, and we can find plenty of these on GitHub. Additionally, the XSS Filter Evasion Cheat Sheet has a couple suggestions for test payloads we can use to test our existing applications.

While it may seem tedious, properly implemented input validation can protect our application from being susceptible to XSS.

Avoiding direct injection

Elements of an application that directly return user input to the browser may not, on a casual inspection, be obvious. We can determine areas of our application that may be at risk by exploring a few questions:

  • How does data flow through our application?
  • What does a user expect to happen when they interact with this input?
  • Where on our page does data appear? Does it become embedded in a string or an attribute?

Here are some sample payloads that we can play with in order to test inputs on our site (again, only our own site!) courtesy of Hacker101. The successful execution of any of these samples can indicate a possible XSS vulnerability due to direct injection.

  • ">

    test

  • '+alert(1)+'
  • "onmouserover="alert(1)
  • //"onmouseover="alert(1)

As a general rule, if you are able to design around directly injecting input, do so. Alternatively, be sure to completely understand the effect of the methods you choose; for example, using innerText instead of innerHTML in JavaScript will ensure that content will be set as plain text instead of (potentially vulnerable) HTML.

Pay attention to your inputs

Softwareudviklere har en markant ulempe, når det kommer til at konkurrere med sort hat eller ondsindede hackere. For alt det arbejde, vi gør for at sikre hver eneste input, der potentielt kan kompromittere vores applikation, behøver en angriber kun finde den, vi savnede. Det er som at installere dødbolte på alle døre, men at lade et vindue være åbent!

Ved at lære at tænke i samme retning som en angriber kan vi dog bedre forberede vores software til at stå op mod dårlige aktører. Spændende som det kan være at sende funktioner så hurtigt som muligt, undgår vi at samle en masse sikkerhedsgæld, hvis vi på forhånd tager os tid til at tænke igennem vores applikationsflow, følge dataene og være opmærksomme på vores input.