XSRF / CSRF (Cross-Site Request Forgery): คู่มือเข้าใจ โจมตี และป้องกันครบถ้วน
🎯 XSRF/CSRF คืออะไร?
Cross-Site Request Forgery (CSRF) ย่อมาจาก XSRF (Cross-Site Request Forgery) เรียกอีกชื่อว่า Sea Surf, Session Riding, Hostile Linking
เป็นการโจมตีทางเว็บที่ หลอกผู้ใช้ที่ล็อกอินอยู่ (Authenticated User) ให้ส่ง Request ไปยัง Web Application โดยไม่ได้ตั้งใจ เพื่อทำการกระทำที่เปลี่ยนแปลงสถานะ (State-changing Action) เช่น:
- เปลี่ยนอีเมล/รหัสผ่าน
- โอนเงิน/ทำธุรกรรม
- เปลี่ยนการตั้งค่าความปลอดภัย
- เพิ่ม/ลบ/แก้ไขข้อมูล
- ยกเลิกคำสั่งซื้อ
⚙️ กลไกการทำงาน (How CSRF Works)
- Victim ล็อกอิน เข้าระบบเป้าหมาย (เช่น bank.com) - มี Session Cookie อยู่ในเบราว์เซอร์
- Attacker สร้างหน้าเว็บ/อีเมล/ลิงก์ ที่ฝัง Request ไปยัง bank.com (เช่น `
` หรือ Form auto-submit)
- Victim เยี่ยมชมหน้าเว็บของ Attacker (หรือเปิดอีเมล HTML)
- Browser ส่ง Request ไป bank.com พร้อม Cookie Session ของ Victim อย่างอัตโนมัติ (Same-origin Policy ไม่บล็อก Cross-origin Request ที่เป็น GET/POST Form)
- Bank.com ประมวลผล Request คิดว่ามาจากผู้ใช้จริง (เพราะ Cookie ถูกต้อง) → โอนเงินสำเร็จ
- Victim ไม่รู้ตัว จนตรวจสอบบัญชี
🔑 จุดสำคัญ: ทำไม CSRF ถึงทำได้?
- Browser ส่ง Cookie อัตโนมัติ ทุกครั้งที่ Request ไป Domain นั้น (Credential Included)
- Server ไม่ตรวจสอบว่า Request มาจาก UI ของตัวเองจริงๆ (Missing Anti-CSRF Token)
- Attacker ไม่ต้องขโมย Cookie/Session - ให้ Browser ของ Victim ทำงานแทน
- ทำงานได้กับ State-changing Requests (POST, PUT, DELETE, PATCH) - GET ควรเป็น Idempotent (แต่บางระบบทำ State Change ด้วย GET - ช่องโหว่ร้ายแรง)
🎭 ตัวอย่างการโจมตี CSRF จริง
fetch('https://bank.com/transfer', {
method: 'POST',
credentials: 'include', // ส่ง Cookie ไปด้วย
body: new URLSearchParams({to: 'attacker', amount: '10000'})
});
🛡️ วิธีป้องกัน CSRF (เรียงตามความมีประสิทธิภาพ)
1. Synchronizer Token Pattern (Anti-CSRF Token) - มาตรฐานทองคำ
- Server สร้าง Token แบบสุ่ม คาดเดาไม่ได้ (Cryptographically Random) ต่อ Session/Request
- Token ต้องส่งมาพร้อม Request (Hidden Form Field, Header, Query Param)
- Server Verify Token ก่อนประมวลผล State-changing Action
- Token ต้อง: Unique per Session/Request, Unpredictable, Expired, Tied to User Session
X-CSRF-Token: a1b2c3d4e5f6...
2. SameSite Cookie Attribute (Modern Defense - รองรับ Browser ใหม่ทั้งหมด)
| Value | พฤติกรรม | เหมาะสำหรับ |
| SameSite=Strict | ไม่ส่ง Cookie ใน Cross-site Request ทุกประเภท (รวม Link Click) | High Security (Banking, Admin) |
| SameSite=Lax | ส่ง Cookie ใน Cross-site Top-level Navigation (Link Click) เท่านั้น ไม่ส่งใน Form POST, iframe, AJAX, img | Default ใน Browser ใหม่ สมดุลระหว่าง Security/UX |
| SameSite=None; Secure | ส่ง Cookie ใน Cross-site ทุกกรณี (ต้องใช้ HTTPS) | Third-party Integration, Embedded Widgets |
✅ แนะนำ: Session Cookie ใช้ SameSite=Lax หรือ SameSite=Strict + Secure + HttpOnly
3. Double Submit Cookie Pattern (Stateless)
- Server สร้าง Token → Set ใน Cookie (HttpOnly=False, SameSite=Lax) + ใส่ใน Form/Header
- Client ส่ง Token ทั้งใน Cookie และ Header/Form Field
- Server Compare ค่าทั้งสอง ต้องตรงกัน
- เหมาะกับ Stateless API/SPA ไม่ต้องเก็บ Token ทาง Server
4. Custom Request Header (สำหรับ SPA/API)
- Require Header เฉพาะ:
X-Requested-With: XMLHttpRequest หรือ Custom Header
- Browser ไม่เพิ่ม Custom Header ใน Cross-origin Form Submit อัตโนมัติ
- ต้องใช้ JavaScript (AJAX/Fetch) → Attacker ทำไม่ได้ง่าย
5. User Interaction Verification (High-Value Actions)
- Re-authentication (Password, 2FA, Biometric)
- One-time Token (Email/SMS/App)
- CAPTCHA / reCAPTCHA
- Confirm Dialog (ไม่เพียงพอต่อ Bot แต่วยากำจัด Accidental Click)
6. Referrer / Origin Header Validation (Supplementary)
- Check `Origin` Header (Present ใน POST/PUT/DELETE) ต้อง Match Trusted Origin
- Check `Referer` Header (อาจถูก Strip/Block โดย Privacy Settings/Proxy)
- ⚠️ ไม่พอใจเพียงอย่างเดียว - Spoof ได้ในบางกรณี ใช้เป็น Layer เพิ่มเติม
🔐 CSRF Token Implementation Best Practices
- Generate ด้วย CSPRNG (Cryptographically Secure PRNG) - ไม่ใช่ Math.random()
- Length ≥ 128 bits (32 Hex chars / 24 Base64 chars)
- Per-Session หรือ Per-Request (Per-Request ปลอดภัยกว่า แต่ซับซ้อนกว่า)
- Store ใน Server-side Session (ไม่ใช่ Client-side เท่านั้น)
- Validate ทุก State-changing Endpoint (POST, PUT, DELETE, PATCH)
- Rotate Token หลัง Login, Privilege Change, Sensitive Action
- Log Failed CSRF Attempts (Security Monitoring)
🧪 ทดสอบ CSRF Vulnerability
- Burp Suite: CSRF PoC Generator (Engagement Tools > Generate CSRF PoC)
- OWASP ZAP: CSRF Scanner
- Manual: สร้าง HTML Page ฟอร์ม Submit ไป Target Endpoint → เปิดใน Browser ที่ Login อยู่
- Check: SameSite Cookie, Anti-CSRF Token, Referer/Origin Check
📋 Checklist ป้องกัน CSRF สำหรับ Developer
- [ ] ทุก State-changing Endpoint มี Anti-CSRF Token
- [ ] Token: Random, Long, Tied to Session, Validated Server-side
- [ ] Session Cookie:
SameSite=Lax หรือ Strict + Secure + HttpOnly
- [ ] ไม่อนุญาต State Change ด้วย GET Request
- [ ] Sensitive Actions: Re-auth / 2FA / OTP
- [ ] CORS Policy: Restrict Origins, No Wildcard (*) with Credentials
- [ ] Security Headers:
Cross-Origin-Resource-Policy, Cross-Origin-Opener-Policy
- [ ] Test CSRF ใน CI/CD Pipeline
📚 อ้างอิงมาตรฐาน
- OWASP CSRF Prevention Cheat Sheet
- OWASP Testing Guide: CSRF (WSTG-SESS-005)
- NIST SP 800-53: SC-23 (Session Authenticity)
- RFC 6265bis: SameSite Cookie Attribute
สรุป
XSRF = CSRF - การโจมตีหลอก User ล็อกอิน ส่ง Request เปลี่ยน State ไป App เป้าหมาย
แก่นปัญหา: Browser ส่ง Cookie อัตโนมัติ + Server ไม่ Verify Source ของ Request
ป้องกันหลัก: 1) Anti-CSRF Token (Synchronizer Pattern) 2) SameSite Cookie (Lax/Strict) 3) Double Submit Cookie 4) Custom Header (SPA) 5) Re-auth สำหรับ High-value Actions
SameSite=Lax เป็น Default แล้วใน Browser ใหม่ แต่ยังต้องมี Token เผื่อ Browser เก่า/Edge Case