HTTP header injection

Kas tai per žvėris ir kodėl turėtume juo rūpintis

Kalbant apie saugumo spragas, HTTP header injection gali pasirodyti kaip kažkas techniškai sudėtingo ir tolimo nuo kasdienybės. Tačiau realybė yra visai kitokia – ši pažeidžiamybė gali tapti rimta problema bet kuriai web aplikacijai, nepriklausomai nuo jos dydžio ar sudėtingumo.

Esmė paprasta: užpuolikas bando įterpti papildomų HTTP antraščių į serverio atsakymą, manipuliuodamas vartotojo įvestimi. Skamba abstrakčiai? Įsivaizduokite situaciją, kai jūsų svetainė leidžia vartotojui pasirinkti kalbą, o ši informacija perduodama per URL parametrą. Jei programuotojas nesirūpino tinkamu duomenų valydymu, užpuolikas gali įterpti specialius simbolius (pavyzdžiui, `\r\n`), kurie HTTP protokole reiškia naujos eilutės pradžią, ir taip pridėti savo antraštes.

Kaip veikia HTTP protokolas ir kur slypi spąstai

Norint suprasti šią ataką, reikia truputį pasikasti į HTTP protokolo mechanizmą. Kai jūsų naršyklė bendrauja su serveriu, ji siunčia užklausą, o serveris atsako. Tiek užklausa, tiek atsakymas turi antraštes (headers), kurios perduoda metaduomenis – informaciją apie turinį, slapukus, nukreipimus ir daug ko kita.

Problema kyla tada, kai aplikacija dinamiškai generuoja šias antraštes, naudodama vartotojo pateiktus duomenis. Pavyzdžiui, populiarus scenarijus – nukreipimas (redirect) po sėkmingo prisijungimo:

Location: https://example.com/dashboard?user=Jonas

Jei programuotojas tiesiog įklijuoja vartotojo vardą iš formos lauko, nepatikrinęs jo turinio, atsiranda galimybė įterpti kenkėjiškų duomenų. Užpuolikas gali pateikti tokį „vardą”:

Jonas\r\nSet-Cookie: session=hacker123

Rezultatas? Serveris sugeneruoja atsakymą su papildomomis antraštėmis, kurias užpuolikas kontroliuoja. Tai jau rimta bėda.

Praktiniai atakos scenarijai ir jų pasekmės

Teorija teorija, bet kas iš tikrųjų gali nutikti? Pirmiausia – HTTP Response Splitting. Tai situacija, kai užpuolikas ne tik prideda naujų antraščių, bet ir visiškai atskiria HTTP atsakymą į dvi dalis, sukurdamas tarsi antrą, netikrą atsakymą. Taip galima įterpti kenkėjišką JavaScript kodą, kuris vykdomas aukos naršyklėje.

Antra populiari ataka – slapukų (cookies) manipuliacija. Įterpus `Set-Cookie` antraštę, užpuolikas gali perrašyti esamus slapukus arba sukurti naujus. Tai atveria duris sesijos užgrobimui (session hijacking) – viena pavojingiausių atakų, kai užpuolikas gali prisijungti kaip kitas vartotojas.

Trečias scenarijus – cache poisoning. Jei tarp vartotojo ir serverio yra tarpiniai serveriai (proxy, CDN), užpuolikas gali manipuliuoti cache’inimo antraštes taip, kad kenkėjiškas turinys būtų išsaugotas ir rodomas kitiems vartotojams. Viena sėkminga ataka – ir tūkstančiai paveiktų lankytojų.

Kodas, kuris kviečia bėdą

Pažiūrėkime į realų pavyzdį PHP kalboje, kuris demonstruoja pažeidžiamą kodą:


<?php
$language = $_GET['lang'];
header("Content-Language: " . $language);
?>

Atrodytų nekalta – tiesiog nustato turinio kalbą pagal URL parametrą. Bet kas nutiks, jei kas nors apsilankys tokiu adresu:

http://example.com/page.php?lang=en%0D%0ASet-Cookie:%20admin=true

Čia `%0D%0A` yra URL užkoduoti `\r\n` simboliai. Serveris sugeneruos atsakymą:


Content-Language: en
Set-Cookie: admin=true

Ir štai jau turime problemą – papildomas slapukas, kurio programuotojas nenorėjo.

Panašios problemos kyla ir su nukreipimais. Python Flask pavyzdys:


from flask import redirect, request

@app.route('/redirect')
def redirect_user():
url = request.args.get('url')
return redirect(url)

Jei `url` parametras nevaliduojamas, užpuolikas gali įterpti ne tik kitą domeną (phishing), bet ir papildomas antraštes.

Gynybos strategijos ir praktiniai patarimai

Gera žinia – šios atakos yra visiškai išvengiamos, jei laikomasi kelių pagrindinių principų. Pirmas ir svarbiausias – niekada nepasitikėti vartotojo įvestimi. Visada, be išimčių, validuokite ir valykite visus duomenis, kurie gali patekti į HTTP antraštes.

Modernūs web frameworkai dažniausiai turi įtaisytas apsaugas. Pavyzdžiui, Django automatiškai užkerta kelią header injection atakoms, valydamas antraščių reikšmes. Express.js Node.js aplinkoje taip pat turi apsaugos mechanizmus. Tačiau tai nereiškia, kad galite visiškai atsipalaiduoti – žinoti, kaip veikia apsauga, yra būtina.

Konkretūs patarimai:

Naudokite framework’o funkcijas – vietoj to, kad rankomis konstruotumėte antraštes, naudokite framework’o teikiamas funkcijas. Jos dažniausiai jau turi įtaisytą validaciją.

Baltųjų sąrašų principas – jei leidžiate vartotojui pasirinkti iš kelių variantų (pvz., kalbos), patikrinkite, ar pasirinkimas atitinka laukiamą reikšmę. Vietoj to, kad tiesiog priimtumėte bet kokią įvestį, leiskite tik iš anksto apibrėžtas reikšmes.

Koduokite specialius simbolius – jei vis dėlto reikia naudoti vartotojo duomenis antraštėse, užtikrinkite, kad `\r` ir `\n` simboliai būtų pašalinti arba užkoduoti.

Content Security Policy (CSP) – nors tai tiesiogiai nesustabdo header injection, CSP gali sumažinti žalą, apribodamas, kokį JavaScript kodą naršyklė gali vykdyti.

Testavimas ir pažeidžiamumų aptikimas

Kaip sužinoti, ar jūsų aplikacija yra pažeidžiama? Pirmas žingsnis – rankinis testavimas. Bandykite įterpti `%0D%0A` seką į visus įvesties laukus ir URL parametrus, kurie gali būti naudojami antraštėse. Stebėkite serverio atsakymus naudodami įrankius kaip Burp Suite ar OWASP ZAP.

Automatizuotas skenavimas taip pat gali padėti. Įrankiai kaip Nikto, Acunetix ar Nessus turi testų, skirtų HTTP header injection aptikti. Tačiau nepasitikėkite tik automatizuotais įrankiais – jie gali praleisti subtilias spragas.

Code review procesas turėtų apimti tikrinimą, kaip aplikacija tvarko vartotojo įvestį, ypač vietose, kur generuojamos HTTP antraštės. Ieškokite šių pattern’ų:

– Tiesioginis vartotojo įvesties naudojimas `header()`, `setHeader()` ar panašiose funkcijose
– Nukreipimų (redirect) logika, kuri naudoja vartotojo pateiktus URL
– Slapukų nustatymas su dinaminėmis reikšmėmis
– Custom antraščių kūrimas be validacijos

Realūs incidentai ir pamokos

Istorija žino ne vieną atvejį, kai HTTP header injection privedė prie rimtų saugumo incidentų. 2015 metais buvo aptikta pažeidžiamybė populiariame Python web framework’e, kuri leido užpuolikams įterpti antraštes per neteisingai apdorotus redirect URL. Problema paveikė tūkstančius aplikacijų.

Kitas įdomus atvejis – 2017 metais saugumo tyrėjai demonstravo, kaip HTTP header injection galėjo būti panaudota prieš populiarius CDN tiekėjus. Manipuliuodami cache antraštėmis, jie sugebėjo „nunuodyti” cache ir priversti CDN dalinti kenkėjišką turinį tūkstančiams vartotojų.

Šie incidentai moko svarbios pamokos: net jei naudojate patikimus framework’us ir bibliotekas, svarbu juos nuolat atnaujinti. Saugumo spragos aptinkamos reguliariai, ir tik laiku taikomi patch’ai gali apsaugoti jūsų aplikaciją.

Ką daryti, kai jau per vėlu

Tarkime, aptikote, kad jūsų aplikacija yra pažeidžiama arba, dar blogiau, jau buvo atakuota. Pirmas žingsnis – nedelsiant ištaisyti spragą. Tai reiškia pataisyti kodą, įdiegti validaciją ir išleisti atnaujinimą.

Jei įtariate, kad ataka jau įvyko, reikia atlikti incident response procedūras. Patikrinkite serverio logus, ieškodami įtartinų užklausų su `%0D%0A` ar panašiomis sekomis. Analizuokite, ar nebuvo paveikti vartotojų slapukai ar sesijos.

Jei buvo paveiktas cache, reikės jį išvalyti – tiek aplikacijos lygmenyje, tiek CDN ar proxy serveriuose. Tai gali reikšti trumpą downtime, bet geriau trumpas pertrūkis nei tęsiamas kenkėjiško turinio dalijimas.

Komunikacija su vartotojais taip pat svarbi. Jei buvo paveikti jų duomenys ar sesijos, privalote juos informuoti. Rekomenduokite pakeisti slaptažodžius ir būkite skaidrūs apie incidentą – tai padeda išlaikyti pasitikėjimą.

Saugumas kaip procesas, ne vienkartinis veiksmas

HTTP header injection yra tik viena iš daugelio potencialių saugumo spragų, su kuriomis susiduria web aplikacijos. Svarbiausia pamoka – saugumas negali būti „pridėtas” vėliau, jis turi būti integruotas į visą kūrimo procesą nuo pat pradžių.

Reguliarūs saugumo auditai, code review su saugumo fokusavimu, automatizuoti testai, kurie tikrina įprastas spragas – visa tai turėtų būti standartinė jūsų development workflow dalis. Ir nepamirškite apie komandos mokymą – programuotojai, kurie supranta, kaip veikia atakos, rašo saugesnį kodą.

Galiausiai, sekite saugumo naujienas ir atnaujinimus. Prenumeruokite savo naudojamų framework’ų ir bibliotekų security mailing lists, skaitykite OWASP rekomendacijas, dalyvaukite security bendruomenėje. Saugumas – tai ne paskirties taškas, o nuolatinė kelionė. Ir kuo geriau suprantate grėsmes, tuo geriau galite nuo jų apsisaugoti.

Daugiau

Šablonų įterpimo pažeidžiamumas