în această secțiune, vom descrie câteva principii generale pentru prevenirea vulnerabilităților de scriptare între site-uri și modalități de utilizare a diferitelor tehnologii comune pentru protejarea împotriva atacurilor XSS.
prevenirea scripturilor între site-uri poate fi realizată în general prin intermediul a două straturi de apărare:
- codificați datele la ieșire
- validați intrarea la sosire
puteți utiliza Burp Scanner pentru a scana site-urile web pentru numeroase vulnerabilități de securitate, inclusiv XSS. Logica de scanare de ultimă oră a lui Burp reproduce acțiunile unui atacator calificat și este capabil să obțină o acoperire corespunzătoare ridicată a vulnerabilităților XSS. Puteți utiliza Burp Scanner pentru a obține asigurarea că apărarea împotriva atacurilor XSS funcționează eficient.
codificați datele la ieșire
codificarea trebuie aplicată direct înainte ca datele controlabile de utilizator să fie scrise pe o pagină, deoarece contextul în care scrieți determină ce tip de codificare trebuie să utilizați. De exemplu, valorile dintr-un șir JavaScript necesită un alt tip de scăpare față de cele dintr-un context HTML.
într-un context HTML, ar trebui să convertiți valori care nu sunt pe lista albă în entități HTML:
-
<
convertește la:<
-
>
convertește la:>
într-un context șir JavaScript, valorile non-alfanumerice ar trebui să fie Unicode-a scăpat:
-
<
convertește la:\u003c
-
>
convertește la:\u003e
uneori va trebui să aplicați mai multe straturi de codificare, în ordinea corectă. De exemplu, pentru a încorpora în siguranță introducerea utilizatorului într-un gestionar de evenimente, trebuie să vă ocupați atât de contextul JavaScript, cât și de contextul HTML. Deci, trebuie mai întâi să Unicode-scape de intrare, și apoi HTML-codifica:
<a href="#" onclick="x='This string needs two layers of escaping'">test</a>
validați intrarea la sosire codificarea
este probabil cea mai importantă linie de apărare XSS, dar nu este suficientă pentru a preveni vulnerabilitățile XSS în orice context. De asemenea, ar trebui să validați intrarea cât mai strict posibil în momentul în care este primită pentru prima dată de la un utilizator.
Exemple de validare de intrare includ:
- dacă un utilizator trimite o adresă URL care va fi returnată în răspunsuri, validând că începe cu un protocol sigur, cum ar fi HTTP și HTTPS. În caz contrar, cineva ar putea exploata site-ul dvs. cu un protocol dăunător, cum ar fi
javascript
saudata
. - dacă un utilizator furnizează o valoare care se aștepta să fie numerică, validând că valoarea conține de fapt un număr întreg.
- validarea acelei intrări conține doar un set așteptat de caractere.
validarea intrării ar trebui să funcționeze în mod ideal prin blocarea intrării nevalide. O abordare alternativă, de a încerca să curățați intrarea nevalidă pentru a o face validă, este mai predispusă la erori și ar trebui evitată ori de câte ori este posibil.
lista albă vs Lista neagră
validarea intrărilor ar trebui să utilizeze, în general, liste albe, mai degrabă decât liste negre. De exemplu, în loc să încercați să faceți o listă cu toate protocoalele dăunătoare (javascript
, data
etc.), pur și simplu face o listă de protocoale sigure (HTTP, HTTPS) și interzice nimic nu pe lista. Acest lucru vă va asigura că apărarea dvs. nu se rupe atunci când apar noi protocoale dăunătoare și o va face mai puțin susceptibilă la atacuri care încearcă să ascundă valori nevalide pentru a se sustrage unei liste negre.
permiterea HTML „sigur”
permiterea utilizatorilor să posteze marcaje HTML ar trebui evitată ori de câte ori este posibil, dar uneori este o cerință de afaceri. De exemplu, un site de blog ar putea permite postarea comentariilor care conțin un marcaj HTML limitat.
abordarea clasică este de a încerca să filtreze tag-uri potențial dăunătoare și JavaScript. Puteți încerca să implementați acest lucru folosind o listă albă de etichete și atribute sigure, dar datorită discrepanțelor în motoarele de analiză a browserului și ciudățenii precum mutation XSS, această abordare este extrem de dificil de implementat în siguranță.
opțiunea cea mai puțin proastă este utilizarea unei biblioteci JavaScript care efectuează filtrarea și codificarea în browserul utilizatorului, cum ar fi DOMPurify. Alte biblioteci permit utilizatorilor să furnizeze conținut în format markdown și să convertească markdown-ul în HTML. Din păcate, toate aceste biblioteci au vulnerabilități XSS din când în când, deci aceasta nu este o soluție perfectă. Dacă utilizați unul ar trebui să monitorizeze îndeaproape pentru actualizări de securitate.
notă
în plus față de JavaScript, alte tipuri de conținut, cum ar fi CSS și chiar HTML regulate pot fi dăunătoare în unele situații.
atacuri folosind CSS rău intenționat
cum să preveniți XSS folosind un motor de șabloane
multe site-uri web moderne folosesc motoare de șabloane din partea serverului, cum ar fi Twig și Freemarker pentru a încorpora conținut dinamic în HTML. Acestea definesc de obicei propriul sistem de evadare. De exemplu, în Twig, puteți utiliza filtrul e()
, cu un argument care definește contextul:
{{ user.firstname | e('html') }}
unele alte motoare de șabloane, cum ar fi Jinja și React, scapă de conținutul dinamic în mod implicit, ceea ce previne în mod eficient majoritatea aparițiilor XSS.
vă recomandăm să examinați îndeaproape caracteristicile care scapă atunci când evaluați dacă să utilizați un anumit motor șablon sau cadru.
notă
dacă concatenați direct introducerea utilizatorului în șiruri de șabloane, veți fi vulnerabil la injectarea șablonului de pe server, care este adesea mai gravă decât XSS.
cum să preveniți XSS în PHP
în PHP există o funcție încorporată pentru a codifica entități numite htmlentities
. Ar trebui să apelați această funcție pentru a scăpa de intrarea dvs. atunci când vă aflați într-un context HTML. Funcția trebuie apelată cu trei argumente:
- șirul de intrare.
-
ENT_QUOTES
, care este un steag care specifică toate ghilimelele ar trebui să fie codificate. - setul de caractere, care în majoritatea cazurilor ar trebui să fie UTF-8.
de exemplu:
<?php echo htmlentities($input, ENT_QUOTES, 'UTF-8');?>
când vă aflați într-un context de șir JavaScript, trebuie să introduceți Unicode-escape așa cum este descris deja. Din păcate, PHP nu oferă un API pentru Unicode-escape a string. Aici este un cod pentru a face acest lucru în PHP:
<?php
function jsEscape($str) {
$output = '';
$str = str_split($str);
for($i=0;$i<count($str);$i++) {
$chrNum = ord($str);
$chr = $str;
if($chrNum === 226) {
if(isset($str) && ord($str) === 128) {
if(isset($str) && ord($str) === 168) {
$output .= '\u2028';
$i += 2;
continue;
}
if(isset($str) && ord($str) === 169) {
$output .= '\u2029';
$i += 2;
continue;
}
}
}
switch($chr) {
case "'":
case '"':
case "\n";
case "\r";
case "&";
case "\";
case "<":
case ">":
$output .= sprintf("\u%04x", $chrNum);
break;
default:
$output .= $str;
break;
}
}
return $output;
}
?>
Iată cum să utilizați funcția jsEscape
în PHP:
<script>x = '<?php echo jsEscape($_GET)?>';</script>
alternativ, puteți utiliza un motor de șabloane.
cum de a preveni XSS client-side în JavaScript
pentru a scăpa de intrare de utilizator într-un context HTML în JavaScript, aveți nevoie de propriul codificator HTML, deoarece JavaScript nu oferă un API pentru a codifica HTML. Iată câteva exemple de cod JavaScript care convertește un șir în entități HTML:
function htmlEncode(str){
return String(str).replace(//gi, function(c){
return '&#'+c.charCodeAt(0)+';';
});
}
apoi utilizați această funcție după cum urmează:
<script>document.body.innerHTML = htmlEncode(untrustedValue)</script>
dacă intrarea dvs. se află într-un șir JavaScript, aveți nevoie de un codificator care să efectueze evadarea Unicode. Aici este un eșantion Unicode-encoder:
function jsEscape(str){
return String(str).replace(//gi, function(c){
return '\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4);
});
}
apoi utilizați această funcție după cum urmează:
<script>document.write('<script>x="'+jsEscape(untrustedValue)+'";<\/script>')</script>
cum pentru a preveni XSS în jQuery
cea mai comună formă de XSS în jQuery este atunci când treci de intrare de utilizator la un selector jQuery. Dezvoltatorii Web ar folosi adesea location.hash
și îl vor transmite selectorului, ceea ce ar provoca XSS, deoarece jQuery ar reda HTML-ul. jQuery a recunoscut această problemă și patch-uri logica lor selector pentru a verifica dacă de intrare începe cu un hash. Acum jQuery va face HTML numai dacă primul caracter este <
. Dacă transmiteți date care nu sunt de încredere selectorului jQuery, asigurați-vă că scăpați corect de valoare utilizând funcția jsEscape
de mai sus.
atenuarea XSS folosind Politica de securitate a conținutului (CSP)
Politica de securitate a conținutului (CSP) este ultima linie de apărare împotriva scripturilor între site-uri. Dacă prevenirea XSS eșuează, puteți utiliza CSP pentru a atenua XSS prin restricționarea a ceea ce poate face un atacator.
CSP vă permite să controlați diverse lucruri, cum ar fi dacă scripturile externe pot fi încărcate și dacă scripturile inline vor fi executate. Pentru a implementa CSP, trebuie să includeți un antet de răspuns HTTP numit Content-Security-Policy
cu o valoare care conține politica dvs.
un exemplu CSP este următorul:
default-src 'self'; script-src 'self'; object-src 'none'; frame-src 'none'; base-uri 'none';
această politică specifică faptul că resursele, cum ar fi imaginile și scripturile, pot fi încărcate numai din aceeași origine ca și pagina principală. Deci, chiar dacă un atacator poate injecta cu succes o sarcină utilă XSS, acesta poate încărca doar resurse din originea curentă. Acest lucru reduce foarte mult șansa ca un atacator să poată exploata vulnerabilitatea XSS.
dacă aveți nevoie de încărcare de resurse externe, asigurați-vă că permiteți numai scripturi care nu ajută un atacator să vă exploateze site-ul. De exemplu, dacă lista albă anumite domenii, atunci un atacator poate încărca orice script din acele domenii. Acolo unde este posibil, încercați să găzduiți resurse pe propriul domeniu.
dacă acest lucru nu este posibil, atunci puteți utiliza politica bazată pe hash sau nonce pentru a permite scripturi pe diferite domenii. Un nonce este un șir aleatoriu care este adăugat ca atribut al unui script sau resursă, care va fi executat numai dacă șirul aleatoriu se potrivește cu cel generat de server. Un atacator nu poate ghici șirul randomizat și, prin urmare, nu poate invoca un script sau o resursă cu un nonce valid și astfel resursa nu va fi executată.