การตรวจสอบข้อมูลนำเข้าคือกระบวนการตรวจสอบข้อมูลที่เข้ามาว่าตรงกับรูปแบบ ประเภท และช่วงของค่าที่คาดหวังก่อนที่แอปพลิเคชันจะประมวลผล ตาม OWASP Input Validation Cheat Sheet (2025) การไม่มีการตรวจสอบเป็นต้นเหตุของช่องโหว่ร้ายแรงส่วนใหญ่ การตรวจสอบข้อมูลที่เข้ามาเป็นแนวป้องกันแรกที่ป้องกันไม่ให้ข้อมูลที่ไม่ถูกต้องหรือเป็นอันตรายเข้าสู่ระบบ
ประเด็นสำคัญ
การตรวจสอบข้อมูลนำเข้าคือการตรวจสอบว่าข้อมูลที่เข้าสู่แอปพลิเคชันจากผู้ใช้ บริการภายนอก หรือส่วนประกอบอื่นตรงตามเกณฑ์ที่คาดหวัง เกณฑ์เหล่านี้รวมถึงประเภทข้อมูล (สตริง ตัวเลข วันที่) รูปแบบ (อีเมล URL โทรศัพท์) ช่วงของค่า (อายุ 18 ถึง 120) ความยาว (รหัสผ่าน 8 ถึง 128 อักขระ) และอักขระที่อนุญาต (เฉพาะตัวอักษรละติน ตัวเลข ยัติภังค์) หากไม่มีการตรวจสอบ แอปพลิเคชันอาจประมวลผลข้อมูลที่ก่อให้เกิดข้อผิดพลาดขณะรันไทม์ ความเสียหายของข้อมูล หรือช่องโหว่ด้านความปลอดภัย
การไม่มีการตรวจสอบข้อมูลนำเข้าคือต้นเหตุของช่องโหว่ เช่น SQL Injection, XSS, Command Injection, Path Traversal และ Buffer Overflow ตาม MITRE CWE (2025) CWE-20 (Improper Input Validation) อยู่ในอันดับสองของการจัดอันดับข้อผิดพลาดซอฟต์แวร์ที่อันตรายที่สุด การตรวจสอบคือแนวป้องกันแรกในแบบจำลองความปลอดภัย Defense in Depth: มันตัดข้อมูลที่ไม่ถูกต้องก่อนที่จะไปถึงส่วนประกอบอื่น ๆ ของระบบ
การตรวจสอบปฏิเสธข้อมูลที่ไม่ตรงตามเกณฑ์ การทำความสะอาด (การล้าง) แก้ไขข้อมูลโดยการลบหรือหลบหลีกส่วนที่อันตราย ตัวอย่างเช่น เมื่อป้อนเนื้อหา HTML การตรวจสอบอาจตรวจสอบความยาวของข้อความ ในขณะที่การทำความสะอาดลบแท็ก script ผ่านไลบรารี HTML Purifier หรือ DOMPurify การทำความสะอาดไม่ได้แทนที่การตรวจสอบ: ทั้งสองทำงานคู่กัน การตรวจสอบคือนโยบาย "อนุญาต/ห้าม" ส่วนการทำความสะอาดคือ "ล้างแล้วก่อนใช้งาน"
การตรวจสอบถูกจัดประเภทตามความลึกของการตรวจสอบ การตรวจสอบรูปแบบนั้นง่ายที่สุดและเร็วที่สุด ส่วนการตรวจสอบทางธุรกิจซับซ้อนที่สุดและขึ้นอยู่กับบริบท ทั้งสามระดับต้องถูกนำไปใช้ตามลำดับ: ก่อนอื่นรูปแบบ จากนั้นความหมาย จากนั้นตรรกะทางธุรกิจ การข้ามระดับใด ๆอาจนำไปสู่การทำงานผิดปกติของระบบหรือช่องโหว่
| ระดับ | ตรวจสอบอะไร | ตัวอย่าง |
|---|---|---|
| รูปแบบ | ประเภทข้อมูล ความยาว นิพจน์ปกติ | อีเมลมี @ ความยาว 5-100 |
| ความหมาย | ความถูกต้องเชิงตรรกะของค่า | วันเกิดไม่อยู่ในอนาคต |
| การตรวจสอบทางธุรกิจ | สอดคล้องกับกฎทางธุรกิจ | จำนวนเงินโอนไม่เกินยอดคงเหลือ |
การตรวจสอบประเภทข้อมูล ขนาด รูปแบบ และอักขระที่อนุญาต นำไปใช้ผ่านนิพจน์ปกติ ประเภทในตัวของภาษา และไลบรารีการตรวจสอบ ตัวอย่าง: การตรวจสอบ UUID (รูปแบบ 8-4-4-4-12 เลขฐานสิบหก) การตรวจสอบหมายเลขโทรศัพท์ (เฉพาะตัวเลข + ที่จุดเริ่มต้น 7 ถึง 15 อักขระ) การตรวจสอบจำนวนเต็ม (ค่าอยู่ในช่วง Integer.MIN_VALUE — Integer.MAX_VALUE) การตรวจสอบรูปแบบคือระดับขั้นต่ำที่จำเป็นสำหรับฟิลด์ป้อนข้อมูลใด ๆ
การตรวจสอบความถูกต้องเชิงตรรกะของข้อมูลในบริบทของโดเมน ตัวอย่างเช่น วันที่เริ่มต้นไม่ช้ากว่าวันที่สิ้นสุด อายุอยู่ในขอบเขตที่สมเหตุสมผลสำหรับระบบ พิกัดอยู่ในพื้นที่ให้บริการ การตรวจสอบเชิงความหมายต้องอาศัยความเข้าใจบริบททางธุรกิจและไม่สามารถทำได้จากรูปแบบเพียงอย่างเดียว ตัวอย่าง: ฟิลด์ "จำนวนตั๋ว" อาจผ่านการตรวจสอบรูปแบบ (จำนวนเต็ม > 0) แต่เชิงความหมายแล้วไม่สามารถเกินจำนวนที่นั่งว่างได้
ระดับที่ซับซ้อนที่สุด — การตรวจสอบว่าข้อมูลสอดคล้องกับกฎทางธุรกิจของแอปพลิเคชัน ตัวอย่าง: ผู้ใช้ไม่สามารถลบผู้ดูแลระบบเพียงคนเดียว จำนวนเงินสั่งซื้อไม่เกินวงเงินเครดิต สินค้าสั่งได้เฉพาะเมื่อมีในสต็อก การตรวจสอบทางธุรกิจมักต้องใช้การสอบถามฐานข้อมูลหรือบริการภายนอก และดำเนินการหลังจากการตรวจสอบรูปแบบและความหมาย ข้อผิดพลาดการตรวจสอบทางธุรกิจเป็นสาเหตุที่พบบ่อยที่สุดของความไม่พอใจของผู้ใช้
การตรวจสอบฝั่งไคลเอนต์ (ในเบราว์เซอร์หรือแอปมือถือ) จำเป็นสำหรับความสะดวกของผู้ใช้: ผลตอบรับทันทีโดยไม่ต้องส่งข้อมูลไปยังเซิร์ฟเวอร์ อย่างไรก็ตาม การตรวจสอบฝั่งเซิร์ฟเวอร์คือวิธีเดียวที่เชื่อถือได้ เนื่องจากโค้ดฝั่งไคลเอนต์สามารถเลี่ยงได้เสมอ ส่งคำขอผ่านเครื่องมือนักพัฒนา Postman หรือพร็อกซี (Burp Suite) — การตรวจสอบฝั่งไคลเอนต์ก็สิ้นสุดลง ตาม PortSwigger Research (2025) แอปพลิเคชันเว็บที่ทดสอบมากกว่า 90% พึ่งพาการตรวจสอบฝั่งไคลเอนต์เพียงอย่างเดียวสำหรับอย่างน้อยหนึ่งฟิลด์
การตรวจสอบฝั่งไคลเอนต์สามารถปิดใช้งานปุ่มส่ง เน้นข้อผิดพลาด และแสดงคำแนะนำ การตรวจสอบฝั่งเซิร์ฟเวอร์คือการตรวจสอบบังคับของทุกพารามิเตอร์ แม้ว่าไคลเอนต์จะตรวจสอบแล้วก็ตาม การทำการตรวจสอบซ้ำทั้งสองระดับเป็นแนวปฏิบัติมาตรฐาน เซิร์ฟเวอร์ต้องตรวจสอบข้อมูลราวกับว่าไม่มีไคลเอนต์อยู่ นี่รับประกันการป้องกันจากคำขอที่ถูกแก้ไข การโจมตีอัตโนมัติ และไคลเอนต์ที่เป็นอันตราย
บนเว็บ — แอตทริบิวต์ HTML5 (required, pattern, min/max, type="email") และ JavaScript ในแอปมือถือ — ตัวตรวจสอบฟิลด์ข้อความแบบเนทีฟ (InputFilter ใน Android, textField(:shouldChangeCharactersIn:) ใน iOS) React Hook Form และ Formik สำหรับ React, Vuelidate สำหรับ Vue, Angular Reactive Forms — ไลบรารียอดนิยมสำหรับการตรวจสอบฝั่งไคลเอนต์ ทั้งหมดรองรับกฎที่กำหนดเองและการตรวจสอบแบบไม่พร้อมกัน (การตรวจสอบความไม่ซ้ำกันของชื่อผู้ใช้บนเซิร์ฟเวอร์)
// ตัวอย่างการตรวจสอบฝั่งเซิร์ฟเวอร์ด้วย Express และ Joi
const Joi = require('joi');
const userSchema = Joi.object({
email: Joi.string()
.email()
.required()
.max(255),
age: Joi.number()
.integer()
.min(18)
.max(120)
.required(),
password: Joi.string()
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,128}$/)
.required()
});
app.post('/api/users', async (req, res) => {
const { error, value } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({
error: error.details[0].message
});
}
// value — ข้อมูลที่ตรวจสอบแล้วและปลอดภัย
const user = await User.create(value);
res.status(201).json(user);
});
แอปมือถือกำหนดข้อกำหนดพิเศษสำหรับการตรวจสอบข้อมูล หน้าจอเล็กลง — ข้อผิดพลาดต้องสั้นกระชับ แป้นพิมพ์ต้องตามบริบท (ตัวเลขสำหรับการป้อนตัวเลข) และการตรวจสอบต้องไม่พร้อมกันเพื่อไม่ให้บล็อก UI แพลตฟอร์มเนทีฟมีกลไกการตรวจสอบในตัวที่ควรใช้เป็นค่าเริ่มต้น Material Design Guidelines สำหรับ Android และ Human Interface Guidelines สำหรับ iOS มีคำแนะนำโดยละเอียดเกี่ยวกับการแสดงข้อผิดพลาดการตรวจสอบ
Jetpack Compose นำเสนอแนวทางแบบประกาศในการตรวจสอบผ่านการจัดการสถานะ ฟิลด์ป้อนข้อมูลแต่ละฟิลด์ผูกกับสถานะ (MutableState) และข้อผิดพลาดคำนวณจากค่าปัจจุบัน ไลบรารี Compose Validator ทำให้การสร้างกฎง่ายขึ้น: required, email, min/max length, pattern การตรวจสอบจะทำงานเมื่อข้อความเปลี่ยนแปลง (onValueChange) หรือเมื่อพยายามส่งแบบฟอร์ม แนะนำให้แสดงข้อผิดพลาดเฉพาะหลังจากการส่งครั้งแรกหรือหลังจากผู้ใช้พิมพ์เสร็จ (debounce 300-500ms)
SwiftUI ไม่มีกลไกการตรวจสอบแบบฟอร์มในตัว แต่ทำให้ง่ายต่อการนำไปใช้ผ่านCombine และ property wrappers ใช้ @State สำหรับค่าของฟิลด์และพร็อพเพอร์ตี้ที่คำนวณสำหรับข้อผิดพลาด เฟรมเวิร์ก ValidatedPropertyKit ให้ตัวตกแต่งสำเร็จรูป: @Validated().email(), @Validated().range(18...120) คำแนะนำสำหรับ iOS — ใช้ประเภทแป้นพิมพ์ (UIKeyboardType.emailAddress, .numberPad) และการพิมพ์ตัวพิมพ์ใหญ่โดยอัตโนมัติเพื่อลดจำนวนข้อผิดพลาดในระดับการป้อน
Flutter มีคลาส Form และ TextFormField พร้อมการตรวจสอบในตัวผ่านคอลแบ็ก validator แต่ละฟิลด์คืนค่าข้อผิดพลาดเป็นสตริงหรือ null หากข้อมูลถูกต้อง FormState.validate() เรียกใช้การตรวจสอบทุกฟิลด์ของแบบฟอร์ม แพ็กเกจ reactive_forms สำหรับกรณีที่ซับซ้อน: validator ที่กำหนดเอง การตรวจสอบแบบไม่พร้อมกัน กฎแบบไดนามิก Flutter Web และเวอร์ชันมือถือใช้ API เดียวกัน ซึ่งทำให้การบำรุงรักษาง่ายขึ้น
// ตัวอย่างการตรวจสอบฟอร์มใน Flutter
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$')
.hasMatch(value)) {
return 'Enter a valid email';
}
return null;
},
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// ประมวลผลข้อมูลที่ถูกต้อง
}
},
child: Text('ส่ง'),
),
],
),
)
เฟรมเวิร์กสมัยใหม่มีตัวตรวจสอบในตัวที่ครอบคลุม 80% ของความต้องการ ส่วนที่เหลือ 20% ต้องใช้กฎที่กำหนดเอง นิพจน์ปกติ หรือการผสมกฎที่มีอยู่ หลักการสำคัญคือการตรวจสอบควรเป็นแบบประกาศเพื่อให้อ่าน ทดสอบ และบำรุงรักษาได้ง่าย หลีกเลี่ยงตรรกะการตรวจสอบที่กระจายอยู่ตามคอนโทรลเลอร์และหน้าจอ — ย้ายไปไว้ในคลาสหรือสคีมาแยกต่างหาก
| เครื่องมือ | แพลตฟอร์ม | คุณลักษณะ |
|---|---|---|
| Joi | Node.js | สคีมาแบบประกาศ ข้อความที่กำหนดเอง |
| Pydantic | Python | Type hints, การตรวจสอบโมเดลอัตโนมัติ |
| Zod | TypeScript | การอนุมานประเภท การพิมพ์แบบเข้มงวด |
| javax.validation | Java | Bean Validation, @NotNull, @Size, @Pattern |
| FluentValidation | .NET | Fluent API, rulesets, กฎแบบมีเงื่อนไข |
White-list (รายการขาว) — คุณกำหนดว่าข้อมูลใดอนุญาต ทุกอย่างอื่นถูกปฏิเสธ Black-list (รายการดำ) — คุณกำหนดว่าข้อมูลใดถูกห้าม ทุกอย่างอื่นผ่านได้ รายการขาวเชื่อถือได้มากกว่าเสมอ: คุณรู้แน่นอนว่าข้อมูลใดจะผ่าน รายการดำต้องคาดการณ์การโจมตีที่เป็นไปได้ทั้งหมด ซึ่งเป็นไปไม่ได้ ตัวอย่าง: ในการตรวจสอบอายุ ให้ใช้รายการขาว (เฉพาะตัวเลข 18 ถึง 120) แทนรายการดำ (ห้าม "0", "-1", "999999")
นิพจน์ปกติเป็นเครื่องมือที่มีประสิทธิภาพสำหรับการตรวจสอบรูปแบบ แต่สามารถเป็นแหล่งของการโจมตี ReDoS (Regular Expression Denial of Service) บางรูปแบบ (ตัวอย่างเช่น (a+)+b) ทำให้เกิดการย้อนกลับที่รุนแรงบนสตริงยาว ส่งผลให้ CPU ของเซิร์ฟเวอร์ทำงานเต็มกำลัง ใช้ไลบรารี regex ที่ผ่านการพิสูจน์แล้วและจำกัดความยาวของสตริงก่อนใช้นิพจน์ปกติ สำหรับกรณีที่ซับซ้อน (อีเมล URL) ให้ใช้ตัวแยกวิเคราะห์ในตัวของภาษาแทน regex ที่สร้างเอง
แม้แต่นักพัฒนาที่มีประสบการณ์ก็ทำผิดพลาดในการนำการตรวจสอบไปใช้ ที่พบบ่อยที่สุด: การตรวจสอบเฉพาะฝั่งไคลเอนต์ กฎที่เข้มงวดเกินไป (รหัสผ่าน "Must contain uppercase, lowercase, digit, special char, >= 12 chars, must not repeat characters") ข้อความแสดงข้อผิดพลาดที่ไม่มีข้อมูล ("Error: invalid input") และการเพิกเฉยกรณีขอบ (ช่องว่างที่ต้น/ท้าย อักขระ Unicode สตริงว่าง) ข้อผิดพลาดเหล่านี้แต่ละข้อทำให้ UX แย่ลงและอาจลดอัตราแปลงของแบบฟอร์ม
if (value) ไม่แยกสตริงว่างออกจากศูนย์ false หรือ "0"แนวปฏิบัติที่ดีที่สุดคือระบบการตรวจสอบแบบรวมศูนย์ที่ครอบคลุมด้วยการทดสอบหน่วย แต่ละกฎควรถูกทดสอบแยกกัน: ค่าขอบเขต ข้อมูลที่ถูกต้อง การโจมตีทั่วไป (ความพยายาม SQLi, payload XSS, สตริงที่ยาวมาก) การทดสอบการถดถอยของการตรวจสอบป้องกันการทำให้กฎอ่อนแอลงโดยไม่ตั้งใจระหว่างการปรับโครงสร้าง ใช้การทดสอบตามคุณสมบัติ (QuickCheck, fast-check) เพื่อสร้างข้อมูลแบบสุ่มและตรวจสอบว่าการตรวจสอบไม่ล้มเหลวด้วยข้อยกเว้น
คำถามที่พบบ่อย
การตรวจสอบปฏิเสธข้อมูลที่ไม่ถูกต้อง ในขณะที่การทำความสะอาดล้างข้อมูล ตัวอย่างเช่น เมื่อป้อนข้อความ HTML การตรวจสอบจะตรวจสอบความยาวสูงสุด ในขณะที่การทำความสะอาดลบแท็ก script ผ่าน DOMPurify ทั้งสองกระบวนการจำเป็น: การตรวจสอบสำหรับการควบคุมรูปแบบ การทำความสะอาดเพื่อความปลอดภัยของผลลัพธ์
ไม่ ไม่เคย การตรวจสอบฝั่งไคลเอนต์เลี่ยงได้ง่ายผ่านการดักจับและแก้ไขคำขอ ใช้เครื่องมือเช่น Burp Suite หรือเพียงแค่ curl การตรวจสอบฝั่งเซิร์ฟเวอร์คือวิธีเดียวที่เชื่อถือได้ในการปกป้องระบบ การตรวจสอบฝั่งไคลเอนต์มีไว้เพื่อปรับปรุงประสบการณ์ผู้ใช้เท่านั้น
ตรวจสอบประเภท MIME (ไม่ใช่แค่นามสกุลไฟล์) ขนาดไฟล์ และลายเซ็น (ไบต์มหัศจรรย์ที่ต้นไฟล์) ผ่านการตรวจสอบลายเซ็นไฟล์ อย่าไว้วางใจนามสกุลไฟล์ — เปลี่ยนชื่อไฟล์เมื่อบันทึก สำหรับรูปภาพ ให้เข้ารหัสใหม่ด้วยไลบรารีฝั่งเซิร์ฟเวอร์ (ImageMagick, Sharp) ซึ่งจะลบโค้ดที่ฝังอยู่ในข้อมูล EXIF
ReDoS (Regular Expression Denial of Service) คือการโจมตีที่ผู้โจมตีส่งสตริงที่สร้างขึ้นมาเป็นพิเศษซึ่งทำให้เกิดการย้อนกลับที่รุนแรงในนิพจน์ปกติ ผลที่ตามมาคือ CPU ของเซิร์ฟเวอร์โหลด 100% และไม่มีการสร้างการตอบสนอง การป้องกัน: จำกัดความยาวของสตริง กำหนดเวลาหมดสำหรับ regex และใช้รูปแบบที่ผ่านการพิสูจน์แล้ว
ใช่ หากข้อมูลถูกแสดงในWebViewหรือใช้ในบริบท HTML หากแบ็กเอนด์ถูกบุกรุก ข้อมูลอาจมีโค้ดที่เป็นอันตราย ตรวจสอบและทำความสะอาดข้อมูลใด ๆ ที่แสดงให้ผู้ใช้เห็น โดยไม่คำนึงถึงแหล่งที่มา ในแอปมือถือ สิ่งนี้สำคัญเป็นพิเศษสำหรับส่วนประกอบแบบไฮบริด
บทสรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม