Dabartinė padėtis: PHP2Shell. Du kritiniai PHP pažeidžiamumai (CVSS 9,2) leidžia vykdyti kenkėjišką kodą be prisijungimo. Pataisos nuo 2026-10-21.Ką dabar daryti →

Kaip užkirsti kelią XSS PHP: saugiai atremkite Cross-Site Scripting

Kaip kūrėjai PHP programose užkerta kelią Cross-Site Scripting: kontekstui tinkamas kodavimas, automatinis escaping šablonuose, HTML valymas ir Content Security Policy.

Būsena 4 min. skaitymoVadovai

Trumpai: XSS PHP užkertate, kiekvieną išvestį koduodami pagal jos kontekstą: htmlspecialchars() HTML, json_encode() su apsaugos parinktimis JavaScript, patikrintus URL nuorodoms. Šablonai su automatiniu escaping daug ką padaro už jus. Content Security Policy ir HttpOnly slapukai apriboja žalą, jei spraga vis dėlto lieka.

Kodėl Cross-Site Scripting dabar verta patikrinti kartu

2026 m. spalį dėmesys sutelktas į PHP2Shell, du kritinius PHP interpretatoriaus pažeidžiamumus, kuriems pataisos prieinamos nuo 2026-10-21. Daug įmonių šiuo metu tikrina savo žiniatinklio programas. Tai gera proga pažiūrėti ir į nuosavo kodo pažeidžiamumus, kurių joks PHP atnaujinimas neištaiso.

Cross-Site Scripting, trumpiau XSS, yra vienas iš jų. OWASP Top 10 XSS priskiria kategorijai Injection. Skirtingai nei serverio pažeidžiamumo atveju, ataka čia nukreipta prieš jūsų svetainės lankytojus ir naudotojus, pavyzdžiui, prieš klientus parduotuvėje ar darbuotojus administravimo srityje.

Pasekmės gali būti didelės: perimtos administratorių sesijos, pakeistos formos, siunčiančios duomenis trečiosioms šalims, arba suklastotas turinys jūsų svetainėje. Perėmus administratoriaus paskyrą, galima prarasti visišką kontrolę programoje.

Kaip XSS atsiranda PHP programose?

XSS atsiranda, kai programa duomenis iš nepatikimo šaltinio nepatikrintus išveda į puslapį. Naršyklė tuomet nebegali atskirti jūsų turinio nuo įterpto kodo ir vykdo abu.

Skiriamos trys formos. Atspindėto XSS atveju turinys ateina tiesiai iš dabartinės užklausos, pavyzdžiui, iš paieškos frazės URL. Saugomo XSS atveju jis yra duomenų bazėje, pavyzdžiui, komentare ar profilio lauke, ir paliečia kiekvieną, atidarantį puslapį. DOM pagrįstas XSS atsiranda naršyklės JavaScript, kai skriptai rašo reikšmes iš URL į puslapį.

Nepatikimi yra visi duomenys, kurių kode nėra fiksuotai: formų laukai, URL parametrai, slapukai, failų pavadinimai, išorinių sąsajų atsakymai ir turinys iš jūsų pačių duomenų bazės, kuris kažkada atėjo iš išorės.

Išvestis: teisingas kodavimas pagal kontekstą

Svarbiausia taisyklė: koduokite išvedant, ir būtent pagal vietą, kur reikšmė atsidurs. HTML turiniui ir atributams kabutėse tinkamiausia priemonė yra htmlspecialchars(). Maža pagalbinė funkcija padeda nepamiršti parinkčių:

<?php
function e(?string $wert): string
{
    return htmlspecialchars($wert ?? '', ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8');
}
?>
<h2><?= e($produkt['name']) ?></h2>
<input type="text" name="suche" value="<?= e($_GET['q'] ?? '') ?>">

Kitiems kontekstams reikia kitų priemonių:

Kontekstas Saugus metodas
HTML turinys, atributas kabutėse htmlspecialchars() su ENT_QUOTES ir UTF-8
Duomenys JavaScript json_encode() su JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_HEX_QUOT
Parametras URL rawurlencode() atskirai reikšmei
Pilnas URL iš naudotojo įvesties Patikrinti schemą, leisti tik https ir http, tada htmlspecialchars()
Atributai be kabučių, įvykių valdikliai, CSS vengti, ten reikšmių neįterpti

Duomenims, kurių reikia skriptui, duomenų atributas arba JSON blokas dažniausiai yra tvarkingiausias kelias:

<?php
$daten = json_encode($konfiguration, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
?>
<div id="app" data-konfig="<?= e($daten) ?>"></div>

JavaScript reikšmę tuomet nuskaitote per duomenų atributą, o turinį nustatote su textContent, o ne su innerHTML.

Šablonai, HTML valymas ir karkasai

Šablonų varikliai, tokie kaip Twig ir Blade, išvestį pagal numatymą koduoja automatiškai. Tai pašalina didelę dalį tipinių klaidų. Pavojinga ten, kur šis elgesys sąmoningai išjungiamas, pavyzdžiui, su Twig filtru raw ar Blade sintakse {!! !!}. Tokių vietų kode turėtų būti nedaug, ir jas reikia tikslingai tikrinti kiekvienos peržiūros metu.

Jei jūsų programa sąmoningai turi leisti naudotojų HTML, pavyzdžiui, formatavimą komentaruose ar redakcinėje sistemoje, vien kodavimo nepakanka, nes HTML juk turi būti rodomas. Tuomet reikia patikrintos valymo bibliotekos, tokios kaip HTML Purifier, kuri praleidžia tik fiksuotą leistinų elementų ir atributų sąrašą. Nuosavi filtrai su reguliariaisiais reiškiniais, kaip rodo patirtis, turi spragų.

Svarbu

Ypač patikrinkite administravimo sritis. XSS rodiniuose, kuriuos mato tik administratoriai, dažnai nuvertinamas, bet jis paliečia būtent paskyras su didžiausiomis teisėmis.

XSS paieška esamame PHP kode

Išaugusiose programose pirmasis klausimas dažniausiai yra ne kaip teisingai koduoti, o kur tai iki šiol buvo pamiršta. Pragmatiškas pradžios taškas yra vietų, kur kintamieji išvedami tiesiogiai, paieška:

# Tiesioginė užklausos duomenų išvestis
grep -rnE "(echo|print|<\?=)\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" src/ templates/ --include="*.php"
# Išjungtas automatinis escaping Twig ir Blade
grep -rnE "\|raw|\{!!" templates/ resources/views/

Radiniai yra patikros užduotys, o ne baigtos išvados. Saugomą XSS tokia paieška randa tik iš dalies, nes reikšmės ten ateina iš duomenų bazės. Todėl papildomai patikrinkite visus rodinius, rodančius naudotojų turinį: komentarus, profilius, užsakymų pastabas, pagalbos užklausas. CMS ir parduotuvėse trečiųjų šalių įskiepiai bei temos tikrai priklauso čia, nes ten glūdi didelė išvesties logikos dalis.

Antroji gynybos linija: CSP ir saugūs slapukai

Net ir kruopščiame kode viena vieta gali būti praleista. Tuomet žalą riboja dvi priemonės. Content Security Policy leidžia naršyklei vykdyti tik skriptus iš nustatytų šaltinių ir draudžia įterptus skriptus, jei jie nėra aiškiai leisti:

Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"

Tokią politiką diekite palaipsniui, pirmiausia vien ataskaitų režimu per Content-Security-Policy-Report-Only, nes esamus analizės ar mokėjimo paslaugų įtraukimus dažniausiai reikia papildyti. Kitas antraštes aprašo vadovas Svetainių saugumo antraštės.

Be to, sesijų slapukai turėtų turėti atributą HttpOnly, kad skriptai jų negalėtų nuskaityti. Kaip apskritai apsaugoti sesijas, aprašo vadovas PHP sesijų apsauga. Susijusį pažeidžiamumą duomenų bazės pusėje aptaria Kaip užkirsti kelią SQL injekcijai PHP.

Kaip PHP SOS padeda konkrečiai?

  • Tikriname jūsų programos šablonus ir išvestis dėl trūkstamo ar klaidingo kodavimo.
  • Radinius vertiname pagal pasiekiamumą ir paveiktas paskyras ir parodome konkrečius pataisymus.
  • Content Security Policy diegiame palaipsniui, netrikdydami parduotuvės ar mokėjimų funkcijų.
  • Po pataisymo išbandome iš naujo ir dokumentuojame rezultatą.

Nepriklausomą patikrą aprėpia paslauga Saugumo auditas ir skverbties testas.

Dažni klausimai

Ar htmlspecialchars pakanka nuo XSS?

Įprastam tekstui HTML turinyje ir atributuose kabutėse taip, jei nurodote ENT_QUOTES ir simbolių rinkinį UTF-8. JavaScript, URL ar CSS galioja kitos taisyklės, ten reikia savo, tinkamo kodavimo.

Ar įvestis filtruoti išsaugant, ar išvedant?

Koduokite išvedant, atsižvelgdami į paskirtį. Įvestis gavus verta tikrinti dėl tikėtinumo, pavyzdžiui, ilgio ir formato. Kas filtruoja tik išsaugodamas, praleidžia duomenis iš kitų šaltinių ir apsunkina vėlesnį naudojimą kituose kontekstuose.

Ką duoda Content Security Policy?

Content Security Policy nustato, iš kokių šaltinių naršyklė gali įkelti ir vykdyti skriptus. Ji gali smarkiai apriboti praleisto XSS pažeidžiamumo poveikį, bet neatstoja teisingo kodavimo.

Kaip komentaruose leisti formatavimą, pavyzdžiui, paryškinimą ar nuorodas?

Naudokite patikrintą HTML valymo biblioteką su leistinų elementų ir atributų sąrašu. Nuosavi reguliarieji reiškiniai skriptams pašalinti linkę klysti ir jų naudoti nereikėtų.

Šaltiniai

Skubus kontaktas

Kiekviena valanda svarbi. Parašykite mums dabar.

Trumpai aprašykite sistemą, PHP versiją ir pastebėjimus. Mes atsakysime, išsiaiškinsime padėtį ir dirbsime nuotoliu, kol incidentas bus užbaigtas ir dokumentuotas.

Skubi pagalba