หมวดหมู่: DataTables

API: ดึง dataAPI: ดึง data

ในการออกแบบ API สำหรับดึงข้อมูลจำนวนมาก ( List Data ) เช่น การใช้งานร่วมกับ Library อย่าง DataTables หรือ Tabulator นักพัฒนามักจะเน้นความสะดวกโดยการรับพารามิเตอร์ sort หรือ orderBy จาก Client โดยตรง แต่ถ้าหากขาดการตรวจสอบที่รัดกุม หรือไม่มีการใช้ Allowed List ( Whitelist ) สิ่งนี้จะกลายเป็นช่องโหว่ที่อันตรายอย่างยิ่ง

บทความนี้จะเจาะลึกถึง 2 ประเด็นหลักที่มักถูกมองข้าม: การไม่ตรวจสอบ Data Type และการไม่จำกัด Allowed List ของฟิลด์ที่อนุญาตให้เรียงลำดับ


ช่องโหว่จากการไม่เช็ค Allowed List (Column Whitelisting)

เมื่อ API รับค่าชื่อ Column มาจาก User โดยตรงเพื่อนำไปใส่ใน Query เช่น SELECT * FROM users ORDER BY {user_input} หากไม่มีการตรวจสอบว่า Column นั้น “อนุญาต” ให้เข้าถึงหรือไม่ จะเกิดปัญหาดังนี้

การรั่วไหลของข้อมูล ( Information Disclosure )

Hacker สามารถเดาชื่อ Column ที่เป็นความลับได้ เช่น password_hash, secret_token หรือ internal_remark แม้ว่า API จะไม่ได้ Return ค่าเหล่านี้ออกไปตรง ๆ แต่การสั่ง ORDER BY password_hash จะทำให้ลำดับของข้อมูลเปลี่ยนไป ซึ่งช่วยให้ผู้ไม่หวังดีใช้เทคนิค Inference เพื่อสุ่มหาข้อมูลใน Database ได้

SQL Injection

นี่คือความเสี่ยงที่ร้ายแรงที่สุด หาก Code ของคุณใช้การต่อ String ( String Concatenation ) แทนการใช้ Parameterized Query ( ซึ่งปกติ ORDER BY มักจะใช้ parameter ตรง ๆ ไม่ได้ในหลาย Library ) Hacker อาจใส่คำสั่งอันตรายต่อท้าย เช่น

  • ?sort=id; DROP TABLE users;--
  • ?sort=(CASE WHEN (SELECT ASCII(SUBSTR(password,1,1)) FROM users WHERE id=1)=97 THEN name ELSE id END) ( เทคนิค Blind SQL Injection )

อันตรายจากการไม่เช็ค Data Type ของการ Sort

บางครั้งเราอาจจะเช็คชื่อ Column แล้ว แต่ลืมตรวจสอบ Type หรือ Direction ของการเรียงลำดับ ( เช่น ASC / DESC )

การทำ Denial of Service ( DoS ) ทางทรัพยากร

หาก Hacker ส่งการ Sort ในฟิลด์ที่ไม่ได้ทำ Index ไว้ ( Non-indexed column ) และฐานข้อมูลมีขนาดใหญ่มาก การสั่ง Sort จะบังคับให้ Database ทำ “Full Table Scan” และใช้ CPU / Memory มหาศาลในการจัดเรียงข้อมูลใหม่ทุกครั้งที่เรียก API ส่งผลให้ระบบช้าลงหรือล่มได้

Logic Errors

ในระดับ Application หากเราไม่เช็คว่าค่าที่ส่งมาเป็น String, Number หรือ Boolean อาจเกิด Error ในระดับ Runtime ที่ทำให้ Application Crash หรือเผยแพร่ Stack Trace ที่เป็นข้อมูลภายในของ Server ออกมา


แนวทางการป้องกัน ( Best Practices )

เพื่อความปลอดภัยสูงสุดในการทำ List Data API ควรปฏิบัติดังนี้

ใช้ Allowed List ( Whitelist ) เสมอ

กำหนดให้ชัดเจนว่า Column ไหนบ้างที่อนุญาตให้ Client สั่ง Sort ได้

// ตัวอย่าง Logic การตรวจสอบ
const allowedSortFields = ['id', 'username', 'created_at'];
const sortBy = allowedSortFields.includes(request.query.sort) 
               ? request.query.sort 
               : 'id'; // ค่า Default

ตรวจสอบทิศทาง ( Direction Check )

อย่ารับค่า ASC หรือ DESC มาจาก String โดยตรงโดยไม่มีการตรวจสอบ

const direction = request.query.dir.toUpperCase() === 'DESC' ? 'DESC' : 'ASC';

ปิดการแสดง Error ของ Database

อย่าส่ง Error Message ดิบ ๆ จาก SQL กลับไปให้ User เพราะจะเป็นการบอกโครงสร้าง Table ให้ Hacker ทราบ

ตรวจสอบ Index

ตรวจสอบให้แน่ใจว่า Column ที่เปิดให้ Sort ได้นั้นมีการทำ Index ไว้ใน Database เพื่อป้องกันปัญหา Performance


สรุป

  • การปล่อยให้ Client ควบคุมการ Query ได้อย่างอิสระโดยไม่มีการ Filter คือการเปิดประตูบ้านทิ้งไว้ การใช้ Allowed List คือกำแพงด่านแรกที่สำคัญที่สุดในการปกป้องข้อมูลและเสถียรภาพของระบบครับ
  • การตรวจสอบจริง ๆ แล้วต้องมีทั้งคู่
    • frontend เช็คตั้งแต่ต้นทาง
    • backend เพราะเป็น api อาจจะโดน call ตรง ๆ ผ่านโปรแกรมอื่นที่ไม่ใช้ frontend ของเราก็ได้

อ่านเพิ่มเติม