บทที่ 9 · Part 2 — Identity & Web Security
Web Security Model
HTTP, origin, Same-Origin Policy, cookie, CORS, browser credentials, trusted proxy headers และ TLS termination ที่กำหนด security boundary ของเว็บ
เว็บหนึ่งอาจตั้ง Access-Control-Allow-Origin: * แล้วเชื่อว่า API เปิดเฉพาะ public data
แต่ endpoint เดียวกันใช้ cookie session และ response มีข้อมูลบัญชี หรือ application อาจเชื่อ
X-Forwarded-Host จาก Internet แล้วสร้าง recovery link ไปยัง domain ของ attacker
การป้องกัน Web ต้องเริ่มจากความเข้าใจว่า browser แนบ credential เมื่อไร, script อ่านข้อมูล ข้าม origin ได้หรือไม่ และ proxy ใดเป็นผู้กำหนดข้อมูลที่ application เชื่อ
Learning Outcomes
- อธิบาย HTTP request path, origin และ Same-Origin Policy ได้
- แยก CORS ออกจาก Authentication/Authorization ได้
- เข้าใจ cookie credential และเหตุผลที่เกิด CSRF ได้
- กำหนด trusted proxy chain สำหรับ Host, scheme และ client IP ได้
- วิเคราะห์ TLS termination และ hop ภายในเป็น trust boundaries แยกกันได้
1 Request ผ่านหลาย Trust Boundaries
TLS จาก browser อาจสิ้นสุดที่ CDN หรือ load balancer ไม่ใช่ application ทุก hop ต้องตอบว่า:
- endpoint ใด authenticate peer
- header ใดถูกสร้าง/ล้างโดย proxy
- plaintext ปรากฏและถูก log ที่ใด
- route จาก edge ถึง origin ถูกจำกัดอย่างไร
- application รู้ external scheme/host/client IP จากแหล่งใด
คำว่า “ใช้ HTTPS” จึงต้องระบุ endpoints ไม่ใช่ถือว่าทุกลูกศรได้รับการป้องกันเหมือนกัน
Origin คือ Security Boundary ของ Browser
origin โดยทั่วไปประกอบด้วย tuple:
scheme + host + port
| URL | เทียบกับ https://app.example.com |
|---|---|
https://app.example.com/profile | same origin |
http://app.example.com | different scheme |
https://api.example.com | different host |
https://app.example.com:8443 | different port |
path ไม่ได้สร้าง origin ใหม่ หน้า /public และ /admin ใน origin เดียวกันจึงแชร์ browser
security boundary หลายอย่าง การ host untrusted content ใต้ origin เดียวกับ admin portal เป็น design risk
Same-Origin Policy ทำอะไร
Same-Origin Policy (SOP) จำกัด script จาก origin หนึ่งในการอ่าน/เข้าถึง resource ของอีก origin แต่ไม่ได้ห้าม cross-origin request ทุกชนิด เช่น form, image หรือ navigation ยังส่ง request ได้
ผลสำคัญ:
- attacker site อาจทำให้ browser ส่ง request พร้อม cookie ได้
- SOP อาจกัน script attacker อ่าน response
- server ยังต้องทำ CSRF protection และ authorization
- endpoint ที่มี side effect ห้ามพึ่ง “อีก site อ่าน response ไม่ได้”
SOP เป็น browser control ไม่ป้องกัน server-to-server client, mobile app, curl หรือ bot
Cookie ถูกแนบอัตโนมัติ
browser เลือก cookie จาก domain/path/secure/samesite rules แล้วแนบไปกับ request application code ไม่ต้องอ่าน cookie ก่อนส่ง นี่เป็นทั้งข้อดีของ HttpOnly session และต้นเหตุ CSRF
POST /transfers HTTP/1.1
Host: app.example.com
Cookie: __Host-session=<opaque>
Origin: https://app.example.com
Content-Type: application/json
server ต้องตรวจ authorization และ CSRF ตาม credential transport SameSite ช่วยลด cross-site
sending แต่ไม่ครอบคลุมทุก navigation/integration และไม่แทน anti-CSRF token/origin validation
CORS คือ Permission ให้ Browser อ่าน Response
Cross-Origin Resource Sharing (CORS) เป็น protocol ที่ server ใช้บอก browser ว่า origin ใดอ่าน response และใช้ method/header/credentials ใดได้ ไม่ใช่ firewall หรือ server-side authorization
Simple และ Preflighted Requests
request บางชนิดถูกส่งได้ทันที ส่วน request ที่มี method/header/content type บางแบบจะมี preflight:
OPTIONS /accounts/acc_01 HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PATCH
Access-Control-Request-Headers: authorization, content-type
response ที่อนุญาตแบบเจาะจง:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: PATCH
Access-Control-Allow-Headers: authorization, content-type
Access-Control-Allow-Credentials: true
Vary: Origin
preflight ไม่ใช่ authorization attacker ที่ไม่ใช่ browser เรียก PATCH ตรงได้เสมอ
CORS Failure ที่พบบ่อย
- reflect
Originใดก็ได้กลับไปพร้อม credentials - allow suffix แบบ
endsWith("example.com")จนevil-example.comผ่าน - เชื่อ
nullorigin โดยไม่เข้าใจ sandbox/file context - allow origin ที่ถูก third party takeover
- ลืม
Vary: Originเมื่อ cache response แตกต่างตาม origin - เปิด method/header กว้างและคิดว่า CORS จำกัด API client ทุกชนิด
ใช้ exact allowlist ที่มี owner/lifecycle และแยก public unauthenticated API ออกจาก credentialed API
CORS ไม่ให้สิทธิ์ Business Resource
แม้ origin ถูก allow และ token valid endpoint ยังต้องตรวจ subject-action-resource ตาม Authorization
แยก Site จาก Origin
cookie SameSite ใช้แนวคิด site ซึ่งอิง registrable domain + scheme ไม่เหมือน origin ทุกกรณี
subdomain ต่างกันอาจ cross-origin แต่ same-site ได้ ดังนั้น XSS/subdomain takeover แห่งหนึ่งอาจ
มีผลต่อ cookie/CSRF assumption ของอีก subdomain
อย่าวาง user-generated site, legacy app และ privileged portal ใต้ parent domain เดียวโดยไม่ วิเคราะห์ cookie domain, CORS, CSP และ takeover lifecycle
อย่าเชื่อ Proxy Headers จาก Client
header เหล่านี้เชื่อได้เฉพาะเมื่อ request มาจาก proxy ที่กำหนดและ proxy ล้างค่าจาก client ก่อน:
Forwarded,X-Forwarded-ForX-Forwarded-ProtoX-Forwarded-Host- vendor-specific client IP / TLS identity headers
application ต้องกำหนด trusted proxy hops ไม่ใช้ค่าซ้าย/ขวาสุดแบบเดาสุ่ม
Host Header Injection
ถ้า recovery link สร้างจาก Host ที่ client ควบคุม:
POST /forgot-password HTTP/1.1
Host: attacker.example
email อาจมี link ไปยัง attacker domain พร้อม recovery token ใช้ canonical external base URL จาก trusted configuration และ allowlist host ที่ edge/application แทนการประกอบ security link จาก request header โดยตรง
HTTPS ต้อง Validate Identity
TLS ให้ confidentiality/integrity ของ channel และ server authentication เมื่อ client ตรวจ certificate chain, validity และ hostname ถูกต้อง การปิด verification ทำให้ encryption ไม่มี peer authenticity และเปิด MITM
เพิ่มเติมสำหรับเว็บ:
- redirect HTTP → HTTPS แต่ sensitive cookie ต้องไม่ถูกส่งผ่าน HTTP ตั้งแต่แรก
- ใช้ HSTS หลังประเมิน subdomain/rollout/recovery
- หลีกเลี่ยง mixed content ที่ HTTPS page โหลด active HTTP resource
- cookie ใช้
Secure - origin server จำกัดให้รับจาก edge ที่กำหนด ไม่เปิด bypass path โดยไม่ตั้งใจ
TLS ไม่ป้องกัน XSS, CSRF, broken authorization หรือ plaintext ที่ log หลัง termination
Cache และ Response Boundary
response ที่มีข้อมูลเฉพาะ user ต้องตั้ง cache policy ให้ตรง architecture Shared CDN/proxy cache อาจรั่วข้อมูลข้าม session ถ้า cache key ไม่รวม authorization context หรือ origin
ระวัง:
- cache authenticated response โดย path อย่างเดียว
- response ขาด
Cache-Controlที่เหมาะสม Varyไม่ตรง header ที่เปลี่ยน content- error/debug response ถูก cache
- signed URL ถูกเก็บใน analytics/referrer
อย่าแก้ด้วย no-store ทุก response โดยไม่พิจารณา performance แต่กำหนด data class และ cache owner
Browser Security Headers เป็น Defense in Depth
header สำคัญจะลงรายละเอียดในบท Browser Security แต่ mental model คือ:
| Header/Policy | Boundary ที่ช่วย |
|---|---|
| Content-Security-Policy | จำกัด source/execution และ framing ตาม directive |
| frame-ancestors | จำกัดการ embed/clickjacking |
| X-Content-Type-Options | ลด MIME sniffing |
| Referrer-Policy | จำกัดข้อมูล URL ที่ส่งออก |
| Permissions-Policy | จำกัด browser capabilities |
| HSTS | บังคับ HTTPS สำหรับ host หลัง browser รับ policy |
header ไม่แทน safe rendering, authorization หรือ secure architecture และค่าที่กว้างเกินอาจไม่มีผลจริง
Review Checklist
- ระบุ origin/site ของ frontend, API, admin และ untrusted content
- ทุก TLS termination/hop มี peer, header และ logging boundary ชัด
- cookie domain/path/secure/samesite จำกัดตาม architecture
- CSRF ไม่พึ่ง SOP หรือ SameSite เพียงชั้นเดียว
- CORS ใช้ exact origin allowlist และไม่ถูกใช้แทน authorization
- credentialed response มี
Vary: Origin/cache policy ที่ถูกต้อง - proxy ล้าง forwarded headers และ application กำหนด trusted hops
- security link ใช้ canonical configured origin ไม่เชื่อ Host header
- origin bypass และ mixed-content path ถูกปิด
- authenticated/sensitive response ไม่รั่วผ่าน shared cache
สรุป
Web security เกิดจาก boundary หลายชั้น: browser origin/site, cookie, CORS, TLS endpoint, reverse proxy และ application authorization SOP จำกัดการอ่านข้าม origin แต่ไม่หยุด request และ CORS เป็น browser read permission ไม่ใช่ access control ของ API