ข้าม​ไป​ยัง​เนื้อหา

คำขอ​ข้าม​ต้นทาง​ของ​คลินิก — เบราว์เซอร์​บล็อก​คำ​ตอบ แต่​แถว​ลง​ไป​แล้ว

คอร์ส​ก่อน​หน้า​ปิด CSRF ทิ้ง​ด้วย​หนึ่ง​บรรทัด ใน​กฎ​ขั้น​ต่ำ​ที่ 10 จาก 12 ทรง​ของ​คอร์ส​นั้น​ตั้ง​อยู่​บน และ​ไม่​เคย​ถูก​บอก​ว่า​มัน​ปิด​อะไร​ไป คอร์ส​นี้​เปิด​บรรทัด​นั้น​กลับ​มา​แล้ว​วัด คำถาม​คือ​เบราว์เซอร์​บอก​ว่า​คำขอ​ถูก​บล็อก​ด้วย CORS แล้ว​ฐาน​ข้อมูล​ได้​แถว​เพิ่ม​กี่​แถว คำ​ตอบ​คือ​หนึ่ง​แถว เพราะ​การ​ปฏิเสธ​เกิด​ที่​ขั้น​อ่าน​คำ​ตอบ ไม่ใช่​ที่​ขั้น​ส่ง​คำขอ แล้ว​ธี​สิ​ส​พลิก​อีก​ชั้น ทรง​ที่​ต้อง​ถาม​ปลาย​ทาง​ก่อน​กลับ​กัน​การ​เขียน​ได้​จริง และ GET ที่​เขียน​ฐาน​ข้อมูล ผ่าน​การ​กัน​ของ CSRF ไป​ทั้ง​ดุ้น ตัว​ที่​ปิด​รู​นั้น​ได้​คือ CORS
ความคืบหน้า0 / 8 บทเรียน

คอร์ส​นั้น​เขียน​เอง​ว่า​เรื่อง​นี้​ใหญ่​เกิน​กว่า​บท​ที่​เหลือ​จะ​รับ​ไหว คอร์ส​นี้​คือ​คำ​ตอบ​ของ​บรรทัด​นั้น

คอร์ส​คัด​กรอง​ผู้​เรียก​ของ​คลินิก วาง​กฎ​ขั้น​ต่ำ​ไว้​ก้อน​หนึ่ง แล้ว​ตั้ง​ชื่อ​ก้อน​นั้น​เอง​ว่า SecConfig.kt — กฎขั้นต่ำที่ probe ใช้วัดทุกทรงหลังจากนี้ ใน​ก้อน​นั้น​มี​หนึ่ง​บรรทัด​ที่​ปิด​การ​กัน CSRF ทิ้ง และ​ไม่มี​บท​ไหน​บอก​ว่า​มัน​ปิด​อะไร​ไป

คอร์ส​นั้น​วัด 12 ทรง และ 10 ทรง ใน​นั้น​ตั้ง​อยู่​บน​กฎ​ก้อน​นี้ อีก 2 ทรง​คือ​ทรง​ที่​ไม่มี SecConfig.kt เลย ซึ่ง​เป็น​สอง​ทรง​ที่​คอร์ส​นั้น​วัด​ไว้ ก่อน เขียน​กฎ​ก้อน​นี้​ขึ้น​มา

บท​สุดท้าย​ของ​คอร์ส​นั้น​ยัง​เอ่ย​ถึง CSRF กับ CORS ไว้​ใต้​หัวข้อ​สิ่ง​ที่​จงใจ​ไม่​แตะ เหตุผล​ที่​มัน​ให้​ไว้​ไม่ใช่​ว่า​เรื่อง​นี้​ไม่​สำคัญ แต่​เป็น​ว่า​แปดบท​ที่​เหลือ​รับ​ไม่​ไหว

ก่อน​คอร์ส​นี้ ทั้ง​ไซต์​เอ่ย​ถึง​สอง​เรื่อง​นั้น​รวม​กัน 2 บรรทัด และ​ไม่มี​ใน deviq/ เลย นับ​เมื่อ 2026-09-05 ด้วย​คำ​สั่ง​เดียว โดย​ไม่​นับ​ไดเรกทอรี​ของ​คอร์ส​นี้​เอง คอร์ส​นี้​จึง​เป็น​คอร์ส​แรก​ที่​เป็น​เจ้าของ​เรื่อง​นี้​ทั้ง​เรื่อง

คอร์ส​นี้​อยู่​ใน​ซี​รีส์​เดิม แต่ probe ของ​มัน​สร้าง​โปร​เจ​กต์​ของ​ตัว​เอง ไม่​ได้​ยก​ใบ​เดิม​มา​ต่อ Visit ของ​ที่​นี่​มี​แค่ id กับ note ตาราง​ชื่อ csrf_visit package ชื่อ clinic.csrf และ container เป็น​คนละ​ใบ​กับ​ของ​คอร์ส​นั้น สิ่ง​ที่​ยก​มา​ต่อ​คือ​คำถาม ไม่ใช่​ตัว​งาน

สิ่ง​ที่​คอร์ส​นี้​ทำ​คือ​เปิด​บรรทัด​นั้น​กลับ​มา แล้ว​วัด​ทั้ง​สอง​ด้าน คือ​ด้าน​ที่ server เห็น และ​ด้าน​ที่​เบราว์เซอร์​เห็น

คำถาม​เดียว คำ​ตอบ​สาม​ชั้น และ​ทั้ง​สาม​ชั้น​วัด​เป็น​จำนวน​แถว​กับ​รหัส HTTP

คำถาม​คือ เบราว์เซอร์​บอก​ว่า​คำขอ​ถูก​บล็อก​ด้วย CORS แล้ว​ฐาน​ข้อมูล​ได้​แถว​เพิ่ม​กี่​แถว

ชั้น​ที่​หนึ่ง CORS ไม่​ได้​กัน​การ​เขียน มัน​กัน​การ​อ่าน ทรง​ที่​ปลาย​ทาง​ไม่​ส่ง header ของ CORS สัก​ตัว วัด​ได้​ว่า server ตอบ 200 แถว​เพิ่ม 1 แถว และ Access-Control-Allow-Origin ออก​มา 0 ตัว เบราว์เซอร์​ปฏิเสธ​ที่​ขั้น​อ่าน​คำ​ตอบ

ชั้น​ที่​สอง มี​สอง​ทรง​ที่​กัน​ได้​จริง ทรง​ที่​ต้อง​ถาม​ปลาย​ทาง​ก่อน​ด้วย Content-Type: application/json ได้ OPTIONS = 1 และ POST = 0 คือ​การ​เขียน​ไม่​เคย​เกิด ส่วน​ทรง​ที่​ตั้ง CORS ไว้​แล้ว server ปฏิเสธ​เอง​ด้วย 403 และ​ไม่มี​แถว​ลง

เส้น​แบ่ง​จึง​ไม่​ได้​อยู่​ที่​ข้าม​โดเมน​หรือ​ไม่ มัน​อยู่​ที่ content-type กับ header ซึ่ง​เป็น​ที่​ที่​คน​เข้าใจ​ผิด​กัน​พอดี

ชั้น​ที่​สาม​คม​ที่สุด CORS ปิด​รู​ที่ CSRF เปิด​ทิ้ง​ไว้ GET ที่​เขียน​ฐาน​ข้อมูล​จริง ผ่าน​การ​กัน​ของ CSRF ไป​ทั้ง​ดุ้น ได้ 200 และ +1 แถว ส่วน​คำขอ​เดียวกัน​ใน​ทรง​ที่​ตั้ง CORS ไว้ ได้ 403 และ +0 แถว

สอง​ชุด​การ​วัด ชุด​หนึ่ง​วัด​ฝั่ง server อีก​ชุด​วัด​ฝั่ง​เบราว์เซอร์​จริง

CORS ถูก​บังคับ​ที่​เบราว์เซอร์​เป็น​หลัก ชุด​วัด​ที่​ใช้ HTTP client ล้วน​จึง​วัด​ครึ่ง​ที่​สำคัญ ที่สุด​ไม่​ได้​เลย มัน​ได้​แค่​อ้าง​สเปก คอร์ส​นี้​จึง​มี​ชุด​วัด​สอง​ชุด

  • ฝั่ง server scripts/clinic-cross-origin/probe.py · 64 ข้อ​อ้าง ตรง​ทั้งหมด · 10 ทรง · ออก​ด้วย​รหัส 0
  • ฝั่ง​เบราว์เซอร์ scripts/clinic-cross-origin/browser/ · 500 รอบ · 5 ทรง · ผล​นิ่ง 20 จาก 20 ทุก​ทรง

ความ​นิ่ง​ถูก​วัด​ก่อน ไม่​ได้​ถูก​สมมติ ไซต์​นี้​มี​บันทึก​ของ​ข้อ​อ้าง​ที่​ผิด 20 จาก 20 รอบ บน​เครื่อง​ผู้​เขียน และ​ผิด 0 จาก 20 รอบ​บน runner ด้วย code ชุด​เดียวกัน คือ​แดง​ที่​นี่ เขียว​ที่​โน่น ชุด​นี้​จึง​ต้อง​ผ่าน​การ​วัด​ความ​นิ่ง​ก่อน

มัน​จ่าย​คืน​แล้ว​หนึ่ง​ครั้ง ตั้งแต่​ก่อน​เขียน​บท​แรก สอง​ทรง​ที่​ต่าง​กัน​แค่ Content-Type ให้​ฝั่ง JavaScript เห็น​ข้อความ​เดียวกัน แต่​ฝั่ง server ได้ POST = 1 ใน​ทรง​หนึ่ง และ POST = 0 ใน​อีก​ทรง​หนึ่ง

ประกาศ​ไว้​ตรง​นี้ เพื่อ​ไม่​ให้​ใคร​อ่าน​จบ​แล้ว​เชื่อ​ว่า​ได้​ของ​ที่​คอร์ส​นี้​ไม่​ได้​ให้

  • ไม่​วัด​ความเร็ว ทั้ง​คอร์ส​ไม่มี​หน่วย​เวลา​สัก​ตัว หน่วย​คือ​จำนวน​แถว จำนวน​คำขอ จำนวน header และ​รหัส HTTP เหมือน​สี่​คอร์ส​ก่อน​หน้า​ใน​ซี​รีส์​เดียวกัน
  • ไม่​อ้าง​พฤติกรรม​ข้าม​ไซต์​ของ SameSite ชุด​วัด​ฝั่ง​เบราว์เซอร์​เห็น cookieSeen เป็น false ทุก​ทรง คอร์ส​นี้​จึง​อ้าง​ได้​แค่ literal ที่ server คาย​ออก​มา
  • ไม่​แตะ​เวลา​ที่ preflight ถูก cache ไว้ ข้อ​นั้น​มี​นาฬิกา​อยู่​ข้าง​ใน จึง​ตก​นอก​กฎ ของ​หน่วย​ที่​คอร์ส​นี้​ยอมรับ
  • ไม่​สอน OAuth2 กับ OIDC และ​ไม่​แตะ​หน้า login คอร์ส​ที่ 35 ตัด​ออก​ด้วย​เหตุผล​เดียวกัน
  • ไม่​สอน​การ​เข้า​รหัส​รหัส​ผ่าน เป็น​ของ​คอร์ส security ทั่วไป ไม่ใช่​ของ​คอร์ส​นี้

ต้อง​ผ่าน​คอร์ส​ที่ 35 มา​ก่อน ส่วน​ความ​รู้​เรื่อง CSRF กับ CORS ไม่​ต้อง​มี

  • ผ่าน คอร์ส​คัด​กรอง​ผู้​เรียก​ของ​คลินิก มา​แล้ว เพราะ​คอร์ส​นี้ เปิด​บรรทัด​ที่​คอร์ส​นั้น​ปิด​ไว้ ไม่​ได้​สร้าง​กฎ​ขึ้น​ใหม่
  • อ่าน Kotlin ออก​และ​เคย​เขียน Spring Boot มา​ก่อน ระดับ​ที่​รู้​ว่า bean มา​จาก​ไหน​ก็​พอ
  • ไม่​ต้อง​รู้จัก CSRF หรือ CORS มา​ก่อน ทุก​กลไก​ถูก​อธิบาย​ตอน​ที่​มัน​โผล่​ครั้ง​แรก
  • ต้อง​มี Docker กับ Gradle เพราะ​ทุก​ข้อ​อ้าง​ใน​คอร์ส​นี้​มา​จาก probe ที่​คุณ​รัน​เอง​ได้
  • ตัวเลข​ทุก​ตัว​ผูก​กับ​รุ่น​ที่​ระบุ​ไว้ Spring Boot 4.1.1 · Kotlin 2.4.10 · JDK 25 · และ chromium ที่ Playwright 1.61.0 ปัก​ไว้

แผนผัง​นี้​เติม​ขึ้น​เอง​เมื่อ​บท​เรียน​ถูก​เพิ่ม​เข้า​มา