Pe scurt: Preveniți XSS în PHP codificând fiecare ieșire potrivit contextului ei: htmlspecialchars() pentru HTML, json_encode() cu opțiuni de protecție pentru JavaScript, URL-uri verificate pentru linkuri. Șabloanele cu escaping automat vă scutesc de o mare parte din asta. O Content Security Policy și cookieurile HttpOnly limitează paguba dacă totuși rămâne o vulnerabilitate.
De ce ar trebui verificat acum și Cross-Site Scripting
În octombrie 2026, atenția este îndreptată spre PHP2Shell, două vulnerabilități critice în interpretorul PHP, pentru care există patchuri din 21.10.2026. Multe companii își fac cu această ocazie verificarea aplicațiilor web. Este un prilej bun să analizați și slăbiciunile din codul propriu, pe care nicio actualizare PHP nu le remediază.
Cross-Site Scripting, pe scurt XSS, este una dintre ele. OWASP Top 10 include XSS în categoria Injection. Spre deosebire de o vulnerabilitate a serverului, atacul vizează aici vizitatorii și utilizatorii site-ului dumneavoastră, de exemplu clienții din magazin sau angajații din backend.
Consecințele pot fi considerabile: sesiuni preluate ale administratorilor, formulare manipulate care trimit date către terți sau conținut falsificat pe site-ul dumneavoastră. Dacă un cont de administrator este preluat, se poate ajunge până la controlul complet asupra aplicației.
Cum apare XSS în aplicațiile PHP?
XSS apare când o aplicație afișează într-o pagină, nevalidate, date dintr-o sursă nesigură. Browserul nu mai poate atunci deosebi conținutul dumneavoastră de codul introdus și le execută pe amândouă.
Se disting trei forme. La XSS reflectat, conținutul provine direct din cererea curentă, de exemplu dintr-un termen de căutare din URL. La XSS stocat, el se află în baza de date, de exemplu într-un comentariu sau într-un câmp de profil, și lovește pe oricine accesează pagina. XSS bazat pe DOM apare în JavaScript-ul browserului, când scripturile scriu în pagină valori din URL.
Sunt nesigure toate datele care nu sunt fixate în cod: câmpuri de formular, parametri URL, cookieuri, nume de fișiere, răspunsuri ale interfețelor externe și conținut din propria bază de date care a venit cândva din exterior.
Codificarea corectă a ieșirii, în funcție de context
Regula cea mai importantă este: codificați la afișare, și anume potrivit locului în care ajunge valoarea. Pentru conținut HTML și atribute între ghilimele, htmlspecialchars() este mijlocul potrivit. O mică funcție ajutătoare împiedică uitarea opțiunilor:
<?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'] ?? '') ?>">
Alte contexte cer alte mijloace:
| Context | Metodă sigură |
|---|---|
| Conținut HTML, atribut între ghilimele | htmlspecialchars() cu ENT_QUOTES și UTF-8 |
| Date pentru JavaScript | json_encode() cu JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_HEX_QUOT |
| Parametru într-un URL | rawurlencode() pentru valoarea individuală |
| URL complet dintr-o introducere a utilizatorului | verificați schema, permiteți doar https și http, apoi htmlspecialchars() |
| Atribute fără ghilimele, event handlere, CSS | evitați, nu introduceți valori acolo |
Pentru datele de care are nevoie un script, un atribut de date sau un bloc JSON este de obicei calea cea mai curată:
<?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>
În JavaScript citiți apoi valoarea prin atributul de date și setați conținutul cu textContent în loc de innerHTML.
Șabloane, curățarea HTML și frameworkuri
Motoarele de șabloane precum Twig și Blade codifică în mod implicit ieșirile, automat. Aceasta exclude o mare parte din erorile tipice. Devine periculos acolo unde acest comportament este dezactivat intenționat, de exemplu cu filtrul raw din Twig sau cu sintaxa {!! !!} din Blade. Asemenea locuri ar trebui să fie rare în cod și verificate țintit la fiecare review.
Dacă aplicația dumneavoastră trebuie să permită intenționat HTML de la utilizatori, de exemplu formatări în comentarii sau într-un sistem editorial, codificarea nu este suficientă, deoarece HTML-ul trebuie, de fapt, afișat. Atunci aveți nevoie de o bibliotecă verificată de curățare, precum HTML Purifier, care lasă să treacă doar o listă fixă de elemente și atribute permise. Filtrele proprii cu expresii regulate sunt, din experiență, lacunare.
Verificați în mod special zonele de backend. XSS în vizualizările pe care le văd doar administratorii este adesea subestimat, dar lovește tocmai conturile cu cele mai multe drepturi.
Găsirea XSS în codul PHP existent
În aplicațiile crescute în timp, prima întrebare nu este de obicei cum se codifică corect, ci unde a fost uitat până acum. Un început pragmatic este căutarea locurilor în care variabilele sunt afișate direct:
# Afișări directe ale datelor cererii
grep -rnE "(echo|print|<\?=)\s*\\\$_(GET|POST|REQUEST|COOKIE|SERVER)" src/ templates/ --include="*.php"
# Auto-escaping dezactivat în Twig și Blade
grep -rnE "\|raw|\{!!" templates/ resources/views/
Rezultatele sunt sarcini de verificare, nu constatări finale. XSS stocat este găsit de o asemenea căutare doar în parte, deoarece valorile vin acolo din baza de date. Verificați de aceea suplimentar toate vizualizările care afișează conținut de la utilizatori: comentarii, profiluri, note de comandă, tichete de suport. La CMS-uri și magazine, pluginurile și temele terților intră în mod explicit aici, deoarece acolo se află o mare parte din logica de afișare.
A doua linie de apărare: CSP și cookieuri sigure
Chiar și cu cod atent, un loc poate fi omis. Două măsuri limitează atunci paguba. O Content Security Policy permite browserului doar scripturi din surse stabilite și interzice scripturile încorporate, dacă nu sunt aprobate explicit:
Header always set Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"
Introduceți o asemenea politică treptat, mai întâi în modul de simplă raportare, prin Content-Security-Policy-Report-Only, deoarece integrările existente ale serviciilor de analiză sau de plată trebuie, de regulă, adăugate. Alte antete le descrie ghidul Antete de securitate pentru site-uri.
În plus, cookieurile de sesiune ar trebui să poarte atributul HttpOnly, pentru ca scripturile să nu le poată citi. Cum securizați sesiunile în ansamblu se află în ghidul Cum securizați sesiunile în PHP. O slăbiciune înrudită, din partea bazei de date, tratează Cum preveniți SQL injection în PHP.
Cum ajută PHP SOS concret?
- Verificăm șabloanele și ieșirile aplicației dumneavoastră pentru codificare lipsă sau greșită.
- Evaluăm constatările după accesibilitate și conturile afectate și arătăm corecturi concrete.
- Introducem treptat o Content Security Policy, fără a perturba funcțiile magazinului sau ale plăților.
- După corectare testăm din nou și documentăm rezultatul.
O verificare independentă o descrie serviciul Audit de securitate și test de penetrare.
Întrebări frecvente
Este htmlspecialchars suficient împotriva XSS?
Pentru text obișnuit în conținutul HTML și în atribute între ghilimele, da, dacă indicați ENT_QUOTES și setul de caractere UTF-8. În JavaScript, în URL-uri sau în CSS se aplică alte reguli, acolo este nevoie de o codificare proprie, potrivită.
Ar trebui să filtrez datele de intrare la salvare sau la afișare?
Codificați la afișare, potrivit destinației. Datele de intrare ar trebui să le verificați la primire pentru plauzibilitate, de exemplu lungime și format. Cine filtrează doar la salvare omite datele din alte surse și îngreunează utilizarea ulterioară în alte contexte.
Ce aduce o Content Security Policy?
O Content Security Policy stabilește din ce surse are voie browserul să încarce și să execute scripturi. Poate limita sensibil efectele unei vulnerabilități XSS ratate, dar nu înlocuiește o codificare corectă.
Cum permit formatări precum text îngroșat sau linkuri în comentarii?
Folosiți o bibliotecă verificată de curățare a HTML, cu o listă albă de elemente și atribute permise. Expresiile regulate proprii pentru eliminarea scripturilor sunt predispuse la erori și nu ar trebui folosite.