ebben a részben ismertetünk néhány általános alapelvet a webhelyek közötti szkriptelési sebezhetőségek megelőzésére, valamint az XSS támadások elleni védelem különböző általános technológiáinak használatára.
a Cross-site scripting megelőzés általában két védelmi rétegen keresztül érhető el:
- kódolja a kimeneti adatokat
- a bemenet ellenőrzése érkezéskor
használhatja böfög szkenner, hogy átvizsgálja a weboldalak számos biztonsági rések, beleértve az XSS. A Burp élvonalbeli szkennelési logikája megismétli a képzett támadó cselekedeteit, és képes elérni az XSS sebezhetőségének megfelelő magas lefedettségét. A Burp Scanner segítségével biztosíthatja, hogy az XSS támadások elleni védelme hatékonyan működik.
adatok kódolása a kimeneten
a kódolást közvetlenül a felhasználó által vezérelhető adatok oldalra írása előtt kell alkalmazni, mert a szövegkörnyezet határozza meg, hogy milyen kódolást kell használni. Például a JavaScript-karakterláncon belüli értékek más típusú menekülést igényelnek, mint a HTML-kontextusban.
HTML-környezetben a nem engedélyezőlistán szereplő értékeket HTML-entitásokká kell konvertálni:
-
<
átalakítja a:<
-
>
átalakítja a:>
JavaScript karakterlánc-kontextusban a nem alfanumerikus értékeknek Unicode-mentettnek kell lenniük:
-
<
átalakítja a:\u003c
-
>
átalakítja a:\u003e
néha akkor kell alkalmazni több réteg kódolás, a megfelelő sorrendben. Például ahhoz, hogy biztonságosan beágyazhassa a felhasználói bevitelt egy eseménykezelőbe, mind a JavaScript, mind a HTML kontextussal foglalkoznia kell. Tehát először Unicode-ot kell menekülnie a bemenetből, majd HTML-kódolni:
<a href="#" onclick="x='This string needs two layers of escaping'">test</a>
a bemenet ellenőrzése érkezéskor
a kódolás valószínűleg az XSS védelem legfontosabb vonala, de nem elegendő az XSS sebezhetőségének megakadályozására minden környezetben. A bevitelt a lehető legszigorúbban érvényesítenie kell abban a pontban is, amikor azt először megkapja a felhasználótól.
példák a bemeneti érvényesítésre:
- ha egy Felhasználó olyan URL-t küld be, amelyet a válaszokban visszaad, akkor ellenőrizze, hogy az biztonságos protokollal, például HTTP-vel és HTTPS-vel kezdődik. Ellenkező esetben valaki olyan káros protokollal használhatja ki webhelyét, mint a
javascript
vagy adata
. - ha a Felhasználó olyan értéket ad meg, amely várhatóan numerikus lesz, akkor ellenőrizze, hogy az érték valójában egész számot tartalmaz-e.
- a bemenet ellenőrzése csak egy várható karakterkészletet tartalmaz.
a bemeneti érvényesítésnek ideális esetben Az érvénytelen bemenet blokkolásával kell működnie. Egy alternatív megközelítés, Az érvénytelen bemenet megtisztításának megkísérlése annak érvényessé tétele érdekében, inkább hibákra hajlamos, és ahol csak lehetséges, kerülni kell.
engedélyezőlistára vs feketelistára
Input érvényesítés általában alkalmazni engedélyezőlisták helyett feketelisták. Például ahelyett, hogy megpróbálna listát készíteni az összes káros protokollról (javascript
, data
stb.) , egyszerűen készítsen egy listát a biztonságos protokollokról (HTTP, HTTPS), és tiltson le mindent, ami nem szerepel a listán. Ez biztosítja, hogy a védelem nem szakad meg, amikor új káros protokollok jelennek meg, és kevésbé fogékony a támadásokra, amelyek Az érvénytelen értékek elfedésére törekszenek, hogy elkerüljék a feketelistát.
a “biztonságos” HTML engedélyezése
ahol csak lehetséges, kerülni kell a felhasználók HTML-jelölésének közzétételét, de néha ez üzleti követelmény. Például egy blog webhely lehetővé teheti a korlátozott HTML-jelölést tartalmazó megjegyzések közzétételét.
a klasszikus megközelítés az, hogy megpróbálja kiszűrni a potenciálisan káros címkéket és a Javascriptet. Megpróbálhatja ezt a biztonságos címkék és attribútumok engedélyezőlistájával végrehajtani, de a böngésző elemző motorjainak és az olyan furcsaságoknak köszönhetően, mint a mutáció XSS, ezt a megközelítést rendkívül nehéz biztonságosan megvalósítani.
a legkevésbé rossz megoldás egy JavaScript könyvtár használata, amely szűrést és kódolást végez a felhasználó böngészőjében, például a DOMPurify. Más könyvtárak lehetővé teszik a felhasználók számára, hogy markdown formátumban nyújtsanak tartalmat, és a markdownt HTML-be konvertálják. Sajnos ezeknek a könyvtáraknak időről időre vannak XSS sebezhetőségei, így ez nem tökéletes megoldás. Ha mégis használ egyet, szorosan figyelnie kell a biztonsági frissítéseket.
Megjegyzés
a JavaScript mellett más tartalom, például a CSS, sőt a szokásos HTML is káros lehet bizonyos helyzetekben.
rosszindulatú CSS-t használó támadások
hogyan lehet megakadályozni az XSS-t sablonmotorral
sok modern webhely szerveroldali sablonmotorokat használ, mint például a Twig és a Freemarker a dinamikus tartalom html-be ágyazásához. Ezek általában meghatározzák saját menekülési rendszerüket. Például a Twigben használhatja a e()
szűrőt, a kontextust meghatározó argumentummal:
{{ user.firstname | e('html') }}
néhány más sablonmotor, mint például a Jinja és a React, alapértelmezés szerint elkerüli a dinamikus tartalmat, ami hatékonyan megakadályozza az XSS legtöbb előfordulását.
javasoljuk, hogy alaposan vizsgálja meg a menekülési funkciókat, amikor megvizsgálja, hogy egy adott sablonmotort vagy keretrendszert használ-e.
Megjegyzés
ha közvetlenül összefűzi a felhasználói bevitelt sablonszövegekbe, akkor kiszolgáltatott lesz a kiszolgálóoldali sablonbefecskendezésnek, amely gyakran súlyosabb, mint az XSS.
hogyan lehet megakadályozni az XSS-t a PHP-ben
a PHP-ben van egy beépített funkció a htmlentities
nevű entitások kódolására. Meg kell hívni ezt a funkciót, hogy elkerülje a bemenet, amikor belsejében egy HTML kontextusban. A függvényt három argumentummal kell meghívni:
- a bemeneti karakterlánc.
-
ENT_QUOTES
, ami egy zászló, amely meghatározza az összes idézőjelet kell kódolni. - a karakterkészlet, amelynek a legtöbb esetben UTF-8-nak kell lennie.
például:
<?php echo htmlentities($input, ENT_QUOTES, 'UTF-8');?>
JavaScript karakterlánc-kontextusban Unicode-escape bemenetet kell használnia a már leírtak szerint. Sajnos a PHP nem biztosít API-t a Unicode-escape string számára. Itt van néhány kód erre a PHP-ben:
<?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;
}
?>
a jsEscape
függvény használata a PHP-ben:
<script>x = '<?php echo jsEscape($_GET)?>';</script>
Alternatív megoldásként használhat sablonmotort is.
hogyan lehet megakadályozni az XSS kliensoldalt a JavaScript-ben
ahhoz, hogy elkerülje a felhasználói bemenetet HTML-környezetben a JavaScript-ben, saját HTML-kódolóra van szüksége, mert a JavaScript nem biztosít API-t a HTML kódolásához. Íme néhány példa JavaScript kódot, amely átalakítja a karakterlánc HTML szervezetek:
function htmlEncode(str){
return String(str).replace(//gi, function(c){
return '&#'+c.charCodeAt(0)+';';
});
}
ezután ezt a funkciót a következőképpen használja:
<script>document.body.innerHTML = htmlEncode(untrustedValue)</script>
ha a bemenet egy JavaScript karakterláncban van, akkor szüksége van egy kódolóra, amely Unicode menekülést hajt végre. Itt van egy minta Unicode-kódoló:
function jsEscape(str){
return String(str).replace(//gi, function(c){
return '\u'+('0000'+c.charCodeAt(0).toString(16)).slice(-4);
});
}
ezután ezt a funkciót a következőképpen használja:
<script>document.write('<script>x="'+jsEscape(untrustedValue)+'";<\/script>')</script>
hogyan lehet megakadályozni az XSS-t a jQuery-ben
az XSS leggyakoribb formája a jQuery-ben az, amikor felhasználói bevitelt ad át egy jQuery-választónak. A webfejlesztők gyakran használják a location.hash
– et, és átadják a választónak, ami XSS-t eredményez, mivel a jQuery a HTML-t jeleníti meg. a jQuery felismerte ezt a problémát, és javította a választó logikáját, hogy ellenőrizze, hogy a bemenet hash-val kezdődik-e. Most a jQuery csak akkor jeleníti meg a HTML-t, ha az első karakter <
. Ha nem megbízható adatokat ad át a jQuery választónak, győződjön meg arról, hogy a fenti jsEscape
függvény segítségével helyesen kerülte el az értéket.
az XSS mérséklése tartalombiztonsági házirend (CSP) használatával
tartalombiztonsági házirend (CSP) az utolsó védelmi vonal a webhelyek közötti parancsfájlok ellen. Ha az XSS-megelőzés nem sikerül, a CSP segítségével enyhítheti az XSS-t azáltal, hogy korlátozza a támadó képességeit.
a CSP segítségével különböző dolgokat vezérelhet, például azt, hogy a külső szkriptek betölthetők-e, vagy hogy a Soros szkriptek végrehajtásra kerülnek-e. A CSP telepítéséhez meg kell adnia egy Content-Security-Policy
nevű HTTP válaszfejlécet, amelynek értéke tartalmazza a házirendet.
egy példa CSP a következő:
default-src 'self'; script-src 'self'; object-src 'none'; frame-src 'none'; base-uri 'none';
ez a házirend meghatározza, hogy az erőforrások, például a képek és a szkriptek csak a főoldallal azonos eredetről tölthetők be. Tehát még akkor is, ha a támadó sikeresen be tud fecskendezni egy XSS hasznos terhet, csak az aktuális eredetről tölthet be erőforrásokat. Ez nagymértékben csökkenti annak esélyét, hogy a támadó kihasználhassa az XSS biztonsági rést.
ha külső erőforrások betöltésére van szüksége, győződjön meg róla, hogy csak olyan szkripteket engedélyez, amelyek nem segítik a támadókat a webhely kihasználásában. Például, ha engedélyezőlistára tesz bizonyos tartományokat, akkor a támadó bármilyen szkriptet betölthet ezekből a tartományokból. Ahol lehetséges, próbáljon meg erőforrásokat tárolni a saját domainjén.
ha ez nem lehetséges, akkor hash – vagy nonce-alapú házirendet használhat a szkriptek engedélyezéséhez különböző tartományokban. A nonce egy véletlenszerű karakterlánc, amelyet egy szkript vagy erőforrás attribútumaként adnak hozzá, amely csak akkor kerül végrehajtásra, ha a véletlenszerű karakterlánc megegyezik a szerver által generált karakterlánccal. A támadó nem tudja kitalálni a randomizált karakterláncot, ezért nem tud meghívni egy szkriptet vagy erőforrást érvényes nonce-vel, ezért az erőforrás nem kerül végrehajtásra.