JSON Toolkit

หากไม่ปิด additionalProperties การตรวจสอบ Schema ก็ไม่ได้ตรวจอะไร

สรุปสำคัญ: การตรวจสอบผ่านไม่ได้แปลว่าข้อมูลสะอาด Pydantic โดยค่าเริ่มต้นเมินฟิลด์ที่ไม่รู้จัก, Zod ตัดทิ้ง, Ajv ปล่อยผ่าน — พารามิเตอร์ที่โมเดลมั่วและคีย์พิมพ์ผิดลอดผ่านอย่างเงียบงัน บทความนี้แสดงสามรูปแบบของการยอมรับอย่างเงียบและวิธีที่ครบถ้วน: ปิดออบเจ็กต์ ควบคุมการแปลงชนิด และรัดทุกระดับของการซ้อน

Intermediateอ่านประมาณ 8 นาทีเผยแพร่ 2026-11-02อัปเดต 2026-11-02
JSON ที่มีฟิลด์เกินผ่านการตรวจสอบ

สรุป: โดยค่าเริ่มต้น ตัวตรวจสอบจะเมินฟิลด์ที่ไม่ได้ประกาศแทนที่จะปฏิเสธ หากไม่มี additionalProperties: false การผ่านการตรวจสอบพิสูจน์เพียงว่าฟิลด์ที่ประกาศไว้เรียบร้อยดี

พฤติกรรมที่อันตรายที่สุดของตัวตรวจสอบไม่ใช่การโยน error แต่คือความเงียบ คีย์ที่พิมพ์ผิดหรือพารามิเตอร์ที่โมเดลสมมติขึ้นลอดผ่านการตรวจสอบอย่างเงียบงันและระเบิดในเลเยอร์ธุรกิจ

หนึ่ง: การตรวจสอบที่ "ผ่าน"

{
  "type": "object",
  "properties": {
    "order_id": { "type": "string" },
    "amount": { "type": "number" }
  },
  "required": ["order_id", "amount"]
}

ส่ง {"order_id": "A1", "amount": 50, "reasn_code": "damaged"} — คีย์ที่สามพิมพ์ผิด ผลจาก Ajv ค่าเริ่มต้นคือ ผ่าน ฟิลด์เกินไม่ถูกปฏิเสธและไม่ถูกทำเครื่องหมาย

ในข้อกำหนด JSON Schema ค่าเริ่มต้นของ additionalProperties คือ true: ฟิลด์ที่ไม่ได้ประกาศได้รับอนุญาต

สอง: สามรูปแบบของความเงียบ

Runtime พฤติกรรมเริ่มต้น ผลลัพธ์
Ajv (JS) ปล่อยผ่าน ข้อมูลสกปรกเข้าถึงตรรกะ
Zod z.object ตัดออก ฟิลด์หายไป ออบเจ็กต์สั้นลง
Pydantic v2 เมิน (extra="ignore") เช่นเดียวกัน ไม่มีร่องรอยใน log

การตัดออกแอบแฝงกว่าการปล่อยผ่าน ทั้งสองไลบรารี ล้มเหลวอย่างเงียบงันในลักษณะเดียวกัน โดยค่าเริ่มต้น

สาม: การเรียกเครื่องมือ LLM ขยายปัญหา

อาร์กิวเมนต์ถูกสร้างโดยโมเดล: มันมั่นใจว่าแต่งชื่อฟิลด์และส่ง "3" แทนตัวเลข แพลตฟอร์มกำหนดพารามิเตอร์เป็น JSON Schema แต่ โดยค่าเริ่มต้นไม่บังคับให้ schema ปิดสนิท — โหมด strict ต้องเปิดอย่างชัดเจน และข้อจำกัดทางไวยากรณ์ครอบคลุมเฉพาะเอาต์พุตตรงของโมเดล

{
  "order_id": 4411,
  "refund_amount_usd": 50,
  "reason_code": "damaged",
  "urgent": "yes"
}

เมื่อปิดออบเจ็กต์ reason_code และ urgent จะถูกปฏิเสธ และ error ชี้ไปที่พาธ /reason_code

สี่: วิธีปิด

Ajv: เพิ่ม additionalProperties: false ที่โหนดออบเจ็กต์

import Ajv from "ajv";
const ajv = new Ajv({ allErrors: true });

const schema = {
  type: "object",
  properties: { order_id: { type: "string" }, amount: { type: "number" } },
  required: ["order_id", "amount"],
  additionalProperties: false,
};

const validate = ajv.compile(schema);
validate({ order_id: "A1", amount: 50, reasn_code: "x" }); // false

Zod: เปลี่ยน z.object เป็น z.strictObject หรือโยง .strict() Pydantic: ตั้ง ConfigDict(extra="forbid")

กฎร่วม: การปิดทำเป็นรายระดับ ออบเจ็กต์ที่ซ้อนกันทุกตัวต้องมี additionalProperties: false ของตัวเอง

ห้า: นโยบายการแปลงชนิด

โหมด lax ของ Pydantic แปลง "5" เป็น 5 มีสามนโยบาย: เข้มงวด (ปฏิเสธชนิดที่ผิด), ควบคุม (อนุญาตเฉพาะการแปลงที่ชัดเจนและจำกัดขอบเขต), เปิดกว้าง (เฉพาะข้อมูลภายใน) สำหรับอินพุตที่ไม่น่าเชื่อถือ ให้เลือกข้อ 1 หรือ 2 และบันทึกไว้ในการทดสอบ

หก: เช็กลิสต์การซ้อน

จุด การกระทำ
ออบเจ็กต์ราก additionalProperties: false
ออบเจ็กต์ซ้อนทุกตัว เช่นเดียวกัน
สมาชิกอาร์เรย์ ปิดออบเจ็กต์ใน items ด้วย
enum และช่วง เพิ่ม enum, minimum/maximum
schema ที่สร้างอัตโนมัติ เติมด้วยมือ

เจ็ด: หลังถูกปฏิเสธ

allErrors: true รายงานฟิลด์ที่ละเมิดทั้งหมดในครั้งเดียว; verbose: true ให้เส้นทาง ปัญหาไวยากรณ์ควรถูก parser จับก่อนการตรวจสอบ schema

คำถามที่พบบ่อย

เข้มงวดเกินไปหรือไม่?

ขึ้นกับสัญญา สำหรับอินพุตที่คุณกำหนดเอง ควรปิด; สำหรับข้อมูลบุคคลที่สามที่มีส่วนขยาย ให้ปิดเฉพาะแกนและแยกโซนขยาย

การ strip ของ Zod ปลอดภัยกว่าหรือ?

ไม่: มันปกป้องปลายน้ำโดยแลกกับผู้เรียก error ควรปรากฏเร็วและชัดเจน

โหมด strict ของแพลตฟอร์มแทนการตรวจสอบในเครื่องได้หรือ?

ไม่ได้ ตัว schema เองอาจยังเปิดอยู่ และไวยากรณ์อาจไม่ครอบคลุมอาร์กิวเมนต์ของเครื่องมือ

หลังปิดแล้วข้อมูลเก่าพังเป็นวงกว้าง?

นั่นแหละคือสิ่งที่ต้องเปิดเผย ใช้ allErrors สำรวจ เพิ่มฟิลด์ที่ไม่เป็นอันตราย แก้ฟิลด์ที่เป็นอันตราย

ทางแก้หนึ่งบรรทัด?

ไม่มี แต่การกระทำขั้นต่ำ: ตรวจว่าทุก type: "object" ตามด้วย additionalProperties: false