10.1 Same-Origin Policy (SOP)
SOP là nguyên tắc bảo mật cốt lõi của browser: JS từ origin A KHÔNG được đọc dữ liệu từ origin B.
Origin = scheme + host + port
https://example.com:443/path1 ┐
https://example.com:443/path2 │ cùng origin
https://example.com/ ┘ (port 443 ngầm)
http://example.com ✗ scheme khác
https://api.example.com ✗ host khác (subdomain ≠ same)
https://example.com:8080 ✗ port khác
Tại sao cần SOP?
Không có SOP, JS từ evil.com có thể:
- Đọc cookie của bank.com
- Gửi AJAX request đến bank.com (với cookie của user)
- Đọc response → steal data
SOP block tất cả → web mới an toàn. Nhưng có lúc cần legitimate cross-origin → cần CORS để mở "ngoại lệ".
10.2 CORS — Cross-Origin Resource Sharing
CORS là cơ chế server "cho phép" origin khác đọc response của mình. Browser thực thi.
Simple request — chỉ check response headers
Request đáp ứng: GET/HEAD/POST + content type form/text/url-encoded + không có custom header → "simple". Browser gửi luôn, sau đó kiểm response:
# Browser tự thêm
Origin: https://app.example.com
# Server response
Access-Control-Allow-Origin: https://app.example.com
# Hoặc: Access-Control-Allow-Origin: * (any origin)
Nếu header thiếu / không match origin → browser block JS đọc response. Request vẫn đến server (đó là lý do CSRF vẫn nguy hiểm — xem 10.3).
Preflight — OPTIONS request
Request "non-simple" (PUT/DELETE/PATCH, custom header, JSON body) → browser gửi OPTIONS preflight trước:
# Preflight (browser tự gửi)
OPTIONS /api/data HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
# Server response
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 # cache preflight 1 day
# Sau đó browser mới gửi PUT thật
PUT /api/data ...
Credentials (cookies)
Cross-origin request mặc định KHÔNG gửi cookies. Để gửi:
fetch('https://api.example.com/me', {
credentials: 'include' // gửi cookies
});
Server phải:
Access-Control-Allow-Origin: https://app.example.com # KHÔNG được "*"
Access-Control-Allow-Credentials: true
CORS error phổ biến
- "No 'Access-Control-Allow-Origin' header" → server thiếu header
- "Wildcard cannot be used with credentials" → khi
credentials: include, không được dùng* - "Method PUT not allowed" → server không khai báo method
10.3 CSRF — Cross-Site Request Forgery
User đã login bank.com (có cookie session). Sau đó visit evil.com. Trang evil chứa:
<form action="https://bank.com/transfer" method="POST">
<input name="to" value="attacker">
<input name="amount" value="1000">
</form>
<script>document.forms[0].submit();</script>
Browser tự gửi cookie session bank.com → bank.com tin là user → chuyển tiền. CORS không giúp vì JS evil không cần đọc response, chỉ cần gửi request.
Phòng tránh CSRF
1. SameSite cookie (modern, easy)
Set-Cookie: session=...; SameSite=Lax; Secure; HttpOnly
Browser không gửi cookie với cross-site POST → request đến bank.com không có cookie → bank reject. Default Chrome 80+.
2. CSRF Token (truyền thống)
Server gửi CSRF token trong form. Khi submit, server check token match session.
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="abc123xyz">
<input name="amount">
</form>
Evil.com không biết token (SOP chặn đọc trang bank) → không tạo được form hợp lệ.
3. Custom header
API JSON yêu cầu header X-Requested-With: XMLHttpRequest hoặc Content-Type: application/json. Browser bắt buộc preflight → phát hiện cross-origin.
4. Double-submit cookie
Token gửi cả qua cookie và body. Server check 2 cái khớp. Evil không đặt được cookie cho bank.com.
5. Origin / Referer header check
Server check Origin hoặc Referer header có khớp domain không.
10.4 XSS — Cross-Site Scripting
Attacker chèn JavaScript vào trang của bạn → script chạy trong browser của user khác → đánh cắp cookie, session, làm việc thay user.
3 loại XSS
1. Stored XSS (nguy hiểm nhất)
Script lưu trên server. Vd: comment chứa <script>...</script> → mọi user xem comment đều chạy script.
2. Reflected XSS
Script trong URL, server "echo" lại trong response. Vd: example.com/search?q=<script>alert(1)</script> → server hiển thị "Bạn tìm: <script>..." → script chạy.
3. DOM-based XSS
Server không liên quan. Attacker dụ user vào URL với fragment chứa script. JS client side đọc location.hash và innerHTML → script chạy.
Phòng tránh XSS
1. Output escaping
Mọi user input khi render HTML phải escape:
< → <
> → >
" → "
& → &
Modern framework (React, Vue, Angular) escape mặc định. Vue: {{ name }} escape; v-html không escape (nguy hiểm).
2. Tránh innerHTML / dangerouslySetInnerHTML
Dùng textContent thay innerHTML. Dùng React {name} thay dangerouslySetInnerHTML.
3. Sanitize HTML khi cần (vd rich text editor)
Dùng DOMPurify để clean HTML user submit, giữ formatting an toàn (b, i, p) bỏ script.
4. CSP (Content Security Policy)
Xem 10.5.
5. HttpOnly cookie
JS không đọc được session cookie → XSS không lấy được session.
Test XSS
# Thử vào form input:
<script>alert('XSS')</script>
<img src=x onerror=alert(1)>
javascript:alert(1)
"><script>alert(1)</script>
10.5 CSP — Content Security Policy
CSP = whitelist các origin được phép load resource (script, style, image, font, ...). Nếu inline script không trong whitelist → browser block.
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.jsdelivr.net;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
Directive phổ biến
default-src: fallback cho mọi loạiscript-src: nguồn script được phépstyle-src: nguồn CSSimg-src: nguồn imageconnect-src: AJAX, WebSocket destinationframe-ancestors: ai có thể nhúng trang này trong iframe (chống clickjacking)
CSP nghiêm: script-src 'self' → chỉ script từ chính domain, không inline, không eval. Phòng XSS hiệu quả.
Khó khăn với CSP nghiêm
- Inline
<script>...</script>bị block → cần dùng nonce hoặc hash - Inline
onclick="..."bị block - Eval bị block (mọi
eval(),new Function())
Best practice: bắt đầu với Content-Security-Policy-Report-Only để chỉ report, không enforce → fix vi phạm trước khi enable thật.
10.6 CDN — Content Delivery Network
CDN = mạng server cache distributed toàn cầu. Cache static asset (image, JS, CSS, video) gần user → giảm latency, giảm load lên origin.
Cách hoạt động
2 loại CDN
- Push CDN: bạn upload asset lên CDN. Phù hợp: nội dung tĩnh, ít thay đổi (images, videos).
- Pull CDN: CDN tự fetch từ origin lần đầu, cache lại. Phù hợp: web hiện đại — 99% dùng pull.
Cache control
CDN tôn trọng HTTP Cache-Control header từ origin:
Cache-Control: public, max-age=31536000, immutable
# CDN cache 1 năm. Phù hợp asset có hash trong URL (vd app.abc123.js)
Cache-Control: public, max-age=300
# Cache 5 phút trên CDN
Cache-Control: no-cache
# Browser revalidate mỗi lần (CDN có thể vẫn cache cho phép 304)
Cache busting
Khi deploy version mới, asset cũ vẫn cache trên CDN. Solution: thêm hash vào filename — app.abc123.js → app.def456.js. Webpack/Vite/Next làm tự động.
Lợi ích
- Latency thấp — server gần user
- Giảm tải origin — đa số request không đến origin
- Bandwidth saving — origin chỉ gửi 1 lần đến CDN, CDN serve nhiều user
- DDoS mitigation — Cloudflare tự filter attack traffic
- TLS termination — CDN handle TLS, origin có thể HTTP nội bộ
Major CDN
Cloudflare, Akamai, Fastly, AWS CloudFront, Google Cloud CDN, Vercel Edge.
10.7 Load Balancer
Load Balancer (LB) phân phối traffic giữa nhiều server backend → scale + failover.
Algorithms
- Round Robin: server lần lượt — đơn giản, đều
- Weighted Round Robin: server mạnh nhận nhiều hơn
- Least Connections: gửi đến server đang có ít connection — tốt cho long-lived connection
- Least Response Time: gửi đến server respond nhanh nhất
- IP Hash: hash(client IP) → cùng client luôn cùng server (sticky session đơn giản)
- Random: random — đôi khi tốt vô cùng (paradox)
- Power of Two Choices: pick 2 random, chọn cái ít connection hơn — gần optimal
Health Check
LB định kỳ ping backend (vd GET /health mỗi 5s). Server fail check → remove khỏi pool. Khi healthy lại → re-add.
Sticky Session (Session Affinity)
Cùng user → cùng backend server (qua cookie hoặc IP hash). Cần khi server lưu state in-memory (vd shopping cart).
Tránh nếu có thể — dùng shared state (Redis) thay sticky → dễ scale.
L4 vs L7 LB (đã học chương 1)
- L4: TCP/UDP — nhanh, không HTTP-aware. AWS NLB, HAProxy TCP mode.
- L7: HTTP — content-based routing (URL, header). AWS ALB, nginx, HAProxy HTTP mode.
Active-Active vs Active-Passive
- Active-Active: tất cả backend đang serve traffic — tốt
- Active-Passive: 1 active, các backup standby. Failover khi active down. Dùng cho database master-slave.
10.8 Reverse Proxy vs Forward Proxy
Forward Proxy
Đứng trước client. Client gửi request qua proxy → proxy chuyển tới Internet.
Use case: corporate firewall, anonymizer (Tor exit node), content filter (school).
Client → Forward Proxy → Internet
Reverse Proxy
Đứng trước server. Client request đến proxy (tưởng đó là server) → proxy chuyển tới backend thật.
Use case: nginx, HAProxy, Cloudflare. Hide backend, LB, TLS termination, caching.
Client → Reverse Proxy → Backend servers
Sự khác biệt: forward proxy đại diện client ra ngoài; reverse proxy đại diện server với client.
10.9 nginx — Swiss Army knife
nginx = web server + reverse proxy + LB + cache + static file server. Tool quan trọng nhất với backend dev.
Reverse proxy đơn giản
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:3000; # forward đến Node app
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Load balancer
upstream backend {
least_conn; # algorithm
server 10.0.0.1:3000 weight=3;
server 10.0.0.2:3000;
server 10.0.0.3:3000 backup; # standby
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
HTTPS termination + redirect
# Redirect HTTP → HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / { proxy_pass http://localhost:3000; }
}
Static file + cache
location /static/ {
alias /var/www/static/;
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
Rate limiting (xem 10.10)
http {
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://backend;
}
}
}
10.10 Rate Limiting
Rate Limiting = giới hạn số request/đơn vị thời gian — chống abuse, DDoS, brute force.
Algorithms
1. Fixed Window
Đếm request trong window cố định (vd "100 req/phút"). Reset đầu mỗi phút. Đơn giản nhưng "burst boundary" (cuối phút này + đầu phút sau có thể spike 200 req trong vài giây).
2. Sliding Window Log
Lưu log timestamp mỗi request. Đếm request trong khoảng [now - 1min, now]. Chính xác nhưng tốn memory.
3. Sliding Window Counter
Combine fixed window cũ + tỷ lệ window mới. Chính xác hơn fixed, ít memory hơn log.
4. Token Bucket
Bucket có capacity N. Mỗi giây refill X token. Mỗi request consume 1 token. Hết token → reject.
capacity = 100, refill = 10/s
Bucket: ●●●●●●●●●●... (max 100)
Request → consume token. Hết → 429 Too Many.
Lý tưởng: cho phép burst (dùng hết bucket nhanh) nhưng giới hạn rate dài hạn.
5. Leaky Bucket
Request vào queue có capacity. Server xử lý với rate cố định. Queue đầy → reject.
Khác token bucket: token bucket cho phép burst, leaky bucket smooth out (rate cố định).
Implement với Redis
// Sliding window log với Redis sorted set
async function checkLimit(userId, max = 100, windowSec = 60) {
const now = Date.now();
const windowStart = now - windowSec * 1000;
const key = `rate:${userId}`;
await redis.zremrangebyscore(key, 0, windowStart); // xoá log cũ
const count = await redis.zcard(key); // đếm hiện tại
if (count >= max) return false; // rate limited
await redis.zadd(key, now, `${now}-${Math.random()}`);
await redis.expire(key, windowSec);
return true;
}
Status code
429 Too Many Requests + header Retry-After: 60 hoặc X-RateLimit-Remaining: 0.
10.11 DDoS — Distributed Denial of Service
Attacker huy động nhiều máy (botnet) gửi request đồng thời → server quá tải → user thật không truy cập được.
Loại tấn công
- Volumetric (L3/L4): flood network với packet/byte. Vd UDP flood, ICMP flood. Defense: scrubbing center của ISP.
- Protocol: SYN flood (consume server connection table), Slowloris (giữ connection mở chậm). Defense: SYN cookies, timeout.
- Application (L7): HTTP flood, request đắt CPU. Defense: rate limit, CAPTCHA, WAF.
Mitigation
- CDN (Cloudflare, AWS Shield) — anycast hấp thụ traffic + filter
- Rate limiting ở edge
- WAF (Web Application Firewall) — block bot pattern
- CAPTCHA cho request đáng nghi
- Auto-scale backend (cẩn thận hết tiền 💸)
- IP reputation + blocklist
Major DDoS attack 2018: GitHub bị 1.35 Tbps memcached amplification — Akamai cứu được trong 10 phút.
Bài tập
Tạo Express server không có CORS config. Tạo HTML page khác origin gọi fetch. Quan sát error trong DevTools Console. Thêm cors middleware → fix.
Gửi request từ JS có Content-Type: application/json + custom header. Quan sát OPTIONS preflight trong DevTools Network. Server phải response gì?
Tạo HTML page có <div>Hi {name}</div> với name từ URL query. Test với ?name=<script>alert(1)</script>. Có alert? Sửa: dùng textContent.
Set CSP script-src 'self'. Trang có <script>alert(1)</script> inline → block. Console show error.
Cài nginx local. Config reverse proxy đến http://localhost:3000 (Node app). Test: curl http://localhost → response của Node.
Implement sliding window log với Redis trong Express. Test: gửi 100 request trong 1s, thấy 429.
Deploy site lên Vercel/Netlify (free). DevTools Network: cột "Server" thấy CDN edge. Header cf-cache-status: HIT hoặc x-vercel-cache: HIT.
🧪 Quiz cuối chương
Câu 1. Same-Origin Policy — origin = ?
Đáp án: scheme + host + port. https://a.com:443 ≠ http://a.com (scheme khác) ≠ https://api.a.com (host khác).
Câu 2. CORS preflight (OPTIONS) trigger khi nào?
Đáp án: non-simple request. Simple request (GET/HEAD/POST + form/text body) không preflight.
Câu 3. CORS có chống CSRF không?
Đáp án: không. CORS chặn JS đọc response, nhưng request vẫn đến server. CSRF lợi dụng "request gửi được" → cần SameSite cookie hoặc CSRF token.
Câu 4. Cách HIỆU QUẢ NHẤT chống CSRF trong app modern?
Đáp án: SameSite cookie + CSRF token. SameSite Lax đã fix nhiều CSRF tự động. Token cho an toàn hơn.
Câu 5. XSS phòng tránh chính bằng?
Đáp án: escape + HttpOnly + CSP. Modern framework (React, Vue) escape mặc định.
Câu 6. Reverse Proxy khác Forward Proxy?
Đáp án: phía client vs phía server. nginx, Cloudflare = reverse proxy. Tor exit, corporate firewall = forward.
Câu 7. Sticky session là?
Đáp án: cùng client → cùng backend. Tránh nếu có thể (dùng shared state Redis) — sticky khó scale.
Câu 8. Token Bucket vs Leaky Bucket?
Đáp án: Token = burst OK, Leaky = smooth. Token bucket phổ biến hơn vì cho phép spike traffic ngắn.
Tổng kết chương 10 — và toàn bộ giáo trình
- ✅ Same-Origin Policy: nguyên tắc bảo mật cốt lõi browser; origin = scheme+host+port
- ✅ CORS: server "cho phép" origin khác đọc response; preflight OPTIONS cho non-simple request
- ✅ CSRF: lợi dụng cookie auto-gửi; phòng = SameSite cookie + CSRF token
- ✅ XSS: chèn JS vào trang; phòng = output escaping + HttpOnly + CSP
- ✅ CSP: whitelist origin được phép load resource
- ✅ CDN: cache distributed; pull CDN phổ biến; cache busting với hash filename
- ✅ Load Balancer: round-robin/least-conn/IP hash; health check; sticky session; L4 vs L7
- ✅ Reverse Proxy (nginx, Cloudflare) vs Forward Proxy
- ✅ nginx: web server + reverse proxy + LB + cache + TLS termination
- ✅ Rate Limiting: fixed/sliding window, token/leaky bucket; status 429
- ✅ DDoS: volumetric/protocol/application; mitigate qua CDN, WAF, rate limit
Bạn đã đi qua 10 chương — từ OSI/TCP-IP đến CDN/Load Balancer. Cùng với DSA + OS, bạn đã có 3/6 trụ cột nền tảng IT. Còn lại: Database, OOP/Design Patterns, System Design.
Đề xuất thực hành sau Networking:
- Cài Wireshark + nginx + Cloudflare account (free) — chơi với chúng
- Đọc High Performance Browser Networking (Ilya Grigorik, free)
- Build mini project: web app HTTPS + nginx reverse proxy + Cloudflare CDN + JWT auth
- Thử CTF hoặc HackTheBox cho web security thực hành
Chúc bạn thành công ở mọi vòng phỏng vấn backend / DevOps / SRE!