Defense-in-depth capstone: ประกอบ guard ทุกชั้นเป็น pipeline เดียว
เจ็ดบทที่ผ่านมาสร้างของครบชุดแล้ว บท1 กาง threat model และ honesty spine, บท2–3 กางภัย — prompt injection ทั้ง direct/indirect, jailbreak, และวินัย “ปฏิบัติต่อทุก content ที่ retrieve มาเป็น untrusted”, บท4–7 สร้างชั้น guard ทีละชั้น: input guard (บท4), output guard/redactor (บท5), least-privilege + approval gate (บท6), data-leak defense (บท7) บทนี้คือ capstone — เอาทั้งสี่ชั้นมา ประกอบเข้าเป็น pipeline เดียว คร่อม agent Order แล้วพิสูจน์ด้วย demo รันได้ว่ามันทำงานอย่างที่ honesty spine บอกไว้ตั้งแต่บท1: guard ลด ความเสี่ยงและ หด blast radiusBlast Radiusขอบเขตความเสียหายเมื่อการโจมตี 'ลอด' detection สำเร็จ — least privilege + approval gate + refund cap + rate limit + idempotency key (reuse #17 เป็น adversarial containment) ทำให้ loop ที่ถูก hijack ยิง refund ซ้ำหรือเกินวงเงินไม่ได้ OWASP พูดตรง ๆ ว่ามาตรการเหล่านี้ 'will not prevent Excessive Agency, but can limit the level of damage caused' — การหด blast radius เมื่อ detection พังคือหัวใจของ containmentArchitecture แต่ไม่ กำจัด ภัย
บทนี้ประกอบ agent Order ตัวเดิม (ความสามารถจาก #15, context layer จาก #16, resilient runtime จาก #17) เข้ากับชั้น guard ทั้งสี่ที่สร้างใน 🔁 บท4, 🔁 บท5, 🔁 บท6, และ 🔁 บท7 — repo kaen-food-ordering (กำลังจัดทำ) ไม่มี tool หรือ store ใหม่มีแต่การ ประกอบ และ residual-attack demo ทุกกติกา API ฝั่งแชตจาก #15 ยังยึดเดิมทุกข้อ
ประกอบทั้งสี่ชั้นเป็น pipeline เดียว — ลำดับคือการตัดสินใจด้านความปลอดภัย
หัวข้อที่มีชื่อว่า “ประกอบทั้งสี่ชั้นเป็น pipeline เดียว — ลำดับคือการตัดสินใจด้านความปลอดภัย”Defense in DepthDefense in Depthการวางหลายชั้น guard ที่แต่ละชั้น 'ไม่สมบูรณ์' แต่รวมกันแล้วกันภัยส่วนใหญ่ได้ — Anthropic: 'individually imperfect, but in unison combine to prevent most threats' และ 'by layering these strategies, you create a robust defense' ทั้งคอร์สคือรูปนี้: input guard → output guard/redactor → least-privilege + approval → data-leak defense ประกอบเป็น guard ชั้นเดียวใน capstone ไม่มีชั้นใดชั้นเดียว 'แก้' injection — ปิดท้ายทุกบทว่า 'security is a process, not a checkbox'Architecture คือการวางหลายชั้นที่แต่ละชั้นไม่สมบูรณ์ แต่ซ้อนกันแล้วกันภัยส่วนใหญ่และกันความเสียหายที่เหลือ — และหัวใจของบทนี้คือ: มันไม่ใช่แค่ “มี guard หลายตัว” แต่คือ เรียง guard ให้ถูกลำดับใน pipeline เดียว ทุกชั้นที่สร้างมาเป็น DelegatingChatClient หรือ policy ที่บังคับใน handler — บทนี้ร้อยมันเข้าด้วยกัน
using Anthropic; // AnthropicClient, AsIChatClient (beta 12.8.0 — pin version)using Microsoft.Extensions.AI; // GA 10.x
AnthropicClient anthropic = new(); // อ่าน ANTHROPIC_API_KEY; x-api-key ใต้ฝากระโปรง
var options = new ChatOptions{ Tools = [ getOrder, // read-only · scope ต่อ caller ใน handler (บท7) getDeliveryStatus, // read-only new ApprovalRequiredAIFunction(AIFunctionFactory.Create(IssueRefund)), // gated (บท6) ], AllowMultipleToolCalls = false, // กัน approval-stickiness (บท6)};
IChatClient agent = anthropic.AsIChatClient("claude-opus-4-8") // bare id, ตัวอย่าง ณ 2026-07 — ไม่ต่อ suffix .AsBuilder() .UseGuardrails() // ชั้นนอกสุด: input screen (บท4) + output validate/redact (บท5) .UseFunctionInvocation() // loop #15; honor approval marker → ปล่อย ToolApprovalRequestContent .UseOpenTelemetry() // continuous monitoring / audit (NIST MANAGE) .Build();UseGuardrails() อยู่ นอก UseFunctionInvocation() เสมอ นี่ไม่ใช่รสนิยม — มันคือการตัดสินใจด้านความปลอดภัยที่ load-bearing: guard ที่อยู่ชั้นนอกจะเห็น input ของผู้ใช้ ก่อน loop จะ dispatch tool ได้ และเห็น output หลัง loop คลี่คลายเสร็จ ถ้าสลับลำดับให้ guard อยู่ใน loop คุณจะ validate input หลังจากที่ tool ถูกเรียกไปแล้ว — สายเกินไป
ชั้นทั้งหมดที่ประกอบกัน แต่ละชั้นเป็นอิสระและไม่สมบูรณ์ในตัว (นั่นคือรูปของ defense-in-depth):
- input screen — normalize + allowlist + injection screen ก่อน dispatch (บท4)
- tool-output screening — ส่ง data ผ่าน
tool_resultที่ JSON-encode แล้ว classifier screen ก่อน model ลงมือ (บท5) - output validation + redaction — structured-output validate ข้อเสนอ refund + redact PII/secret วนทั่ว
Messages[].Contents[]ไม่ใช่แค่.Text(บท5) - least privilege — แยก tool read-only จาก tool ที่มีสิทธิ์;
IssueRefundใช้ credential เฉพาะ + cap ฝั่ง server (บท6) - approval gate — native
ApprovalRequiredAIFunctionที่ block รอมนุษย์จริง (บท6) - handler-side authz + idempotency + cap — reuse idempotency key จาก #17 เป็น containment เชิงปฏิปักษ์ (บท6)
- prompt hygiene + data scoping — ไม่มี secret ใน system prompt,
getOrderscope ต่อ caller (บท7) - audit log — ทุก tripwire, ทุกครั้งที่ขอ refund, ทุกการตัดสิน approval (NIST MANAGE)
Anthropic เรียกการวางชั้นแบบนี้ตรงๆ ว่าเป็นการสร้าง defense ที่แข็ง (S13, verbatim):
“By layering these strategies, you create a robust defense against jailbreaking and prompt injections.”
flowchart TD
U["ผู้ใช้ / ผู้โจมตี"]
subgraph PIPE["pipeline เดียว — ลำดับคือการตัดสินใจด้านความปลอดภัย"]
direction TB
G1["UseGuardrails ชั้นนอกสุด<br/>input screen (บท4)"]
FI["UseFunctionInvocation loop<br/>getOrder · getDeliveryStatus · issueRefund gated"]
G2["กลับออกชั้นนอก<br/>output validate + redact Contents[] (บท5)"]
G1 --> FI --> G2
end
U --> G1
G2 --> OUT["คำตอบถึงผู้ใช้"]
subgraph LAYERS["ชั้น containment ที่บังคับนอก pipeline"]
L1["scope getOrder ต่อ caller (บท7)"]
L2["approval gate + cap + idempotency (บท6)"]
L3["ไม่มี secret ใน prompt (บท7)"]
L4["audit log ทุก tripwire/refund (NIST MANAGE)"]
end
FI -. บังคับที่ handler .-> L1
FI -. containment .-> L2
G1 -. ตั้งค่า .-> L3
G2 -. observability .-> L4
classDef guard fill:#475569,stroke:#1e293b,color:#f8fafc;
classDef engine fill:#b91c1c,stroke:#7f1d1d,color:#f8fafc;
class G1,G2,L1,L2,L3,L4 guard;
class FI engine;
คำบรรยายภาพ: pipeline เดียวที่ UseGuardrails() ห่อ นอก UseFunctionInvocation() — input ของผู้ใช้ผ่าน input screen (บท4) ก่อนเข้า loop (สีแดง = engine ที่ dispatch tool) แล้ว output ไหลกลับออกชั้นนอกให้ validate + redact (บท5) ก่อนถึงผู้ใช้ สี่กล่องสีเทาด้านล่างคือชั้น containment ที่บังคับ นอก pipeline — scope ข้อมูล, approval gate + cap + idempotency, prompt hygiene, และ audit log — ไม่มีชั้นใดชั้นเดียวสมบูรณ์ ซ้อนกันจึงกันภัยส่วนใหญ่และกันความเสียหายที่เหลือ
แผนที่: ชั้นไหนตอบความเสี่ยงข้อไหน
หัวข้อที่มีชื่อว่า “แผนที่: ชั้นไหนตอบความเสี่ยงข้อไหน”มาตรฐานคือ แผนที่ ไม่ใช่ตัวรักษาความปลอดภัยเอง — code guard ที่ประกอบไว้ต่างหากที่ลดความเสี่ยงจริง แต่การวางแผนที่ทับ pipeline ช่วยให้เห็นว่าไม่มีมุมไหนถูกลืม (อ้างโดยเลข/Article แบบเบาๆ):
- input screen (บท4) → OWASP LLM01 Prompt Injection
- output validate + redact (บท5) → LLM05 Improper Output Handling + LLM02 Sensitive Information Disclosure
- least privilege + approval gate + cap (บท6) → LLM06 Excessive Agency; EU AI Act Art. 14 human oversight; least-privilege controls ของ SAIF ที่บท6 อ้างไว้
- prompt hygiene + data scoping (บท7) → LLM07 System Prompt Leakage + LLM02
- rate / loop caps → LLM10 Unbounded Consumption
- ทั้ง posture รวมกัน → NIST GOVERN/MANAGE (S19) + EU AI Act Art. 15 ที่ระบุว่า adversarial robustness เป็นข้อกำหนด ทางกฎหมาย ของระบบ high-risk ไม่ใช่ทางเลือก (S21)
- MITRE ATLAS → เลนส์ red-team ที่ผลิต corpus เคสโจมตีมาทดสอบ pipeline นี้
OWASP LLM05 ตอกย้ำว่าทำไมชั้น output ถึงจำเป็น — output ของ model คือสิ่งที่ผู้โจมตีคุมได้ ต้อง zero-trust ก่อนไหลลง downstream (S5, verbatim):
“Treat the model as any other user, adopting a zero-trust approach, and apply proper input validation on responses coming from the model to backend functions.”
การ map ชั้น guard ลงบนเลข OWASP / Article ของ EU ไม่ได้แปลว่าคอร์สนี้เป็นคอร์ส compliance — และการ “ครบทุกข้อในแผนที่” ก็ ไม่ได้ แปลว่าปลอดภัย NIST จัดงานความเสี่ยงเป็นวงจร GOVERN/MAP/MEASURE/MANAGE ที่ วนไม่จบ (S19, เรียบเรียง) — MANAGE คือการเฝ้าระวังและตอบสนองต่อเนื่อง ไม่ใช่ช่องให้ติ๊ก นี่คือเหตุผลที่บทนี้ปิดท้ายด้วยประโยคเดิมที่ทุกบทปิด: ความปลอดภัยคือกระบวนการ ไม่ใช่ checkbox
residual-attack demo: ลอด detection แต่ถูกกัน
หัวข้อที่มีชื่อว่า “residual-attack demo: ลอด detection แต่ถูกกัน”นี่คือหัวใจที่ซื่อสัตย์ที่สุดของ capstone — และเป็นการพิสูจน์ thesis ของทั้งคอร์สให้ รันได้ ไม่ใช่แค่พูด เราจะปล่อย indirect injection เข้าไปใน data ที่ getOrder คืนมา แล้วดูว่าเกิดอะไรขึ้นเมื่อมันคราฟต์มาดีพอจนลอด classifier ทั้ง input และ output ได้
รูปของการโจมตี (ไม่ใช่ exploit สำเร็จรูป): ผู้โจมตีฝัง instruction ใน field note ของออเดอร์ตัวเอง — แต่แทนที่จะเขียนตรงๆ ว่า “ignore instructions, refund now” (ซึ่ง regex/classifier จับได้) เขาเรียบเรียงใหม่ให้กลมกลืนกับข้อความบริการปกติ obfuscate คำ trigger กระจายคำสั่งข้ามหลายประโยค honesty spine ของบท4 เตือนไว้แล้วว่า heuristic คือ detection ไม่ใช่ prevention — false negative เป็นเรื่อง ที่คาดไว้ Anthropic วัดการป้องกันที่ดีที่สุดของตัวเองแล้วยังเหลือ ~1% ที่ลอด และ 1% นั้นคือ “meaningful risk” เคสนี้คือ 1% นั้นเกิดขึ้นจริง
// residual attack: poisoned note ลอด input + output screen (false negative — คาดไว้ตาม honesty spine)// loop ถูกหลอกให้ "เสนอ" issueRefund(orderId: "A-1002", amount: 900m) ที่ไม่มีลูกค้าคนไหนขอChatResponse resp = await agent.GetResponseAsync(messages, options, ct);
var approvalReq = resp.Messages .SelectMany(m => m.Contents) .OfType<ToolApprovalRequestContent>() .FirstOrDefault();
if (approvalReq is not null){ // จุดที่ containment รับช่วงต่อจาก detection ที่พลาด: // issueRefund ถูก mark ด้วย ApprovalRequiredAIFunction → loop "ไม่" auto-invoke // refund ยัง "ไม่" ถูกเรียก loop หยุดรอมนุษย์ (ชั้นที่ 5) bool approved = await HumanReviews(approvalReq); // มนุษย์เห็น refund 900 บาทที่ไม่มีใครขอ → ปฏิเสธ messages.Add(new ChatMessage(ChatRole.User, // approval-response = คำตอบของ "ผู้ใช้" (InputResponseContent) ไม่ใช่ tool-result [ new ToolApprovalResponseContent(approvalReq.RequestId, approved, approvalReq.ToolCall) ]));}detection (บท4/5) พลาด — แต่ containment (บท6) กันไว้ ได้ เพราะ issueRefund ถูก mark เป็น ApprovalRequiredAIFunction loop จึงปล่อย ToolApprovalRequestContent ออกมาแทนการเรียก tool จริง refund ไม่เกิด จนกว่ามนุษย์จะกด และเมื่อมนุษย์เห็น “refund 900 บาท” ที่ไม่มีบริบทว่าใครขอ เขาก็ปฏิเสธ
และแม้สมมติเลวร้ายสุด — มนุษย์เผลอ rubber-stamp (บท6 เตือนว่า Anthropic วัดได้ว่าผู้ใช้กด approve ~93% ของ prompt) — ชั้น containment ที่เหลือก็ยัง หด blast radius: handler เช็ค authz ใน code, amount cap ฝั่ง server ตัด refund ที่เกินเพดาน, และ idempotency key (reuse จาก #17) กันไม่ให้ loop ที่ถูก hijack ยิง refund ซ้ำ N ครั้ง — loop ที่ถูกยึดจ่ายได้อย่างมากหนึ่งครั้ง ไม่เกินเพดาน ไม่ใช่ N ครั้งไม่จำกัด OWASP พูดเรื่องนี้ตรงๆ ว่า containment ไม่ได้ กำจัด excessive agency แต่ จำกัดความเสียหาย (S6, verbatim):
“will not prevent Excessive Agency, but can limit the level of damage caused.”
Anthropic เสริมด้วยว่ารูป checkpoint แบบนี้ — หยุดรอมนุษย์ที่จุดสำคัญ — คือกลไกควบคุมมาตรฐานของ agent (S16, verbatim):
“Agents can then pause for human feedback at checkpoints or when encountering blockers.”
flowchart TD
ADV["ผู้โจมตี"] -->|"ฝัง payload หลบ classifier"| NOTE["poisoned note<br/>ใน getOrder data"]
NOTE --> DET{"input + output screen<br/>บท4/5"}
DET -->|"false negative — ลอด (คาดไว้)"| PROP["loop เสนอ issueRefund<br/>900 บาท ที่ไม่มีใครขอ"]
PROP --> GATE{"approval gate บท6<br/>ApprovalRequiredAIFunction"}
GATE -->|"loop หยุด · refund ยังไม่ถูกเรียก"| HUMAN["มนุษย์ตรวจ → ปฏิเสธ"]
HUMAN --> SAFE["ถูกกัน · blast radius = 0"]
GATE -.->|"ถึงมนุษย์เผลอกด"| CAP["cap + idempotency (บท6/#17)<br/>refund 1 ครั้ง ≤ เพดาน"]
CAP --> SAFE
classDef danger fill:#b91c1c,stroke:#7f1d1d,color:#f8fafc;
classDef guard fill:#475569,stroke:#1e293b,color:#f8fafc;
classDef ok fill:#166534,stroke:#14532d,color:#f8fafc;
class ADV,NOTE,PROP danger;
class DET,GATE,HUMAN,CAP guard;
class SAFE ok;
คำบรรยายภาพ: สายสีแดงคือการโจมตีที่ ลอด detection ได้ — poisoned note ผ่าน input/output screen แบบ false negative (สิ่งที่ honesty spine คาดไว้) แล้วหลอก loop ให้เสนอ refund ที่ไม่มีใครขอ แต่ชั้น containment สีเทากันไว้: approval gate หยุด loop ก่อน refund จะถูกเรียกจริง มนุษย์ปฏิเสธ → blast radius = 0 (สีเขียว) และแม้มนุษย์เผลอกด cap + idempotency ก็ยังจำกัดให้จ่ายได้อย่างมากหนึ่งครั้งไม่เกินเพดาน detection พลาด containment กัน — นี่คือ thesis ของคอร์สที่รันได้
ส่งต่อ: capstone นี้เชื่อมกลับไปที่ไหน
หัวข้อที่มีชื่อว่า “ส่งต่อ: capstone นี้เชื่อมกลับไปที่ไหน”capstone ไม่ได้ปิดจ๊อบ — มันคือจุดตั้งต้นของงานต่อเนื่อง (MANAGE ที่วนไม่จบ) ขีดเส้นให้ชัดว่าเรื่องไหนไปต่อที่คอร์สไหน:
- การให้คะแนนเคสโจมตี → #13 🔁 evals for AI agents — corpus เคสโจมตีที่คุณ red-team มาทั้งคอร์สนี้คือ input ของ harness วัดผลใน #13 Anthropic เรียกงานนี้ว่า (S13, verbatim) “Red-team your own agent. Before deploying, test your workflow with documents, emails, and tool outputs that deliberately contain injection attempts.” — #18 ผลิต เคสโจมตี, #13 แปลงมันเป็น การวัดผลเชิงระบบ คนละงาน ไม่สอน scoring ซ้ำ
- ความปลอดภัยของ tool-server → #14 🔁 designing MCP servers — ถ้า tool ย้ายไปเป็น MCP server ระยะไกล การรักษา protocol และตัว server (tool-poisoning ใน metadata) เป็นงานของ #14 ที่ #18 ไม่ ทับ — #18 ยืนได้แม้ server เชื่อถือได้เต็มร้อย
- untrusted retrieval / poisoned memory → #16 🔁 context engineering — เส้นทาง memory/retrieval ที่ถูก poison คือ indirect injection อีกช่อง #16 curate context เพื่อคุณภาพ #18 ปฏิบัติต่อสิ่งที่ retrieve มาเป็นศัตรู
- resilient runtime ที่ guard ขี่อยู่ → #17 🔁 agent harness & loop — idempotency key + cap ที่ #17 สร้างเพื่อกัน อุบัติเหตุ ถูก reuse ในบท6/8 เป็น containment เชิง ปฏิปักษ์ รูป wrapper เดียวกัน threat model ตรงข้าม
สรุป — และคำสุดท้ายของคอร์ส
หัวข้อที่มีชื่อว่า “สรุป — และคำสุดท้ายของคอร์ส”capstone ประกอบชั้น guard ทั้งสี่ (input บท4, output บท5, least-privilege/approval บท6, data-leak บท7) เข้าเป็น pipeline เดียวคร่อม agent Order โดย UseGuardrails() ห่อ นอก UseFunctionInvocation() เสมอ — ลำดับคือการตัดสินใจด้านความปลอดภัย แผนที่ OWASP/NIST/EU ทับให้เห็นว่าชั้นไหนตอบความเสี่ยงข้อไหน และ residual-attack demo พิสูจน์ให้เห็นกับตาว่า เมื่อ detection พลาด (ซึ่ง honesty spine บอกว่ามันจะพลาด) containment ยังกันไว้ได้ — detection ลด containment หด รวมกันคือ defense-in-depth
ความปลอดภัยคือกระบวนการ ไม่ใช่ checkbox — ไม่มีชั้นไหนชั้นเดียว “แก้” injection ได้ และ pipeline ที่ประกอบเสร็จก็ไม่ได้ กำจัด ภัย มันเอาชนะการโจมตีส่วนใหญ่และ กัน ส่วนที่เหลือ Anthropic สรุปรูปนี้ไว้ตรงที่สุดว่ามันคือการวางหลายชั้นที่ (S15, verbatim):
“several different overlapping safeguards that may be individually imperfect, but in unison combine to prevent most threats.”
indirect injection ที่ตั้งใจจริงยังลอด detection ได้ — นั่นคือคือเหตุผลที่ containment (least privilege + human gate + cap + idempotency) ไม่ใช่ทางเลือก guard ลด ความเสี่ยงและ หด blast radius มันไม่ กำจัด ภัย และคอร์สนี้จะไม่แกล้งทำเป็นว่ามันทำได้ — ตั้งแต่บทแรกจนบทสุดท้าย
บทนี้อิงต้นทางที่ลงวันที่กำกับ อ่านต่อได้โดยตรง:
- Anthropic, “Mitigate jailbreaks and prompt injections” — การวางชั้น “By layering these strategies, you create a robust defense against jailbreaking and prompt injections.” และ “Red-team your own agent…” (สะพานส่งต่อไป #13)
- Anthropic, “Building safeguards for Claude” — defense in depth: “several different overlapping safeguards that may be individually imperfect, but in unison combine to prevent most threats.”
- Anthropic, “Building Effective Agents” (2024-12-19) — checkpoint / human-in-the-loop: “Agents can then pause for human feedback at checkpoints or when encountering blockers.”
- OWASP, “LLM05:2025 Improper Output Handling” (2025) — zero-trust output: “Treat the model as any other user, adopting a zero-trust approach…”
- OWASP, “LLM06:2025 Excessive Agency” (2025) — containment ไม่กำจัด: “will not prevent Excessive Agency, but can limit the level of damage caused.”
- NIST, “AI 600-1, Generative AI Profile” (2024-07-26) — วงจร GOVERN/MAP/MEASURE/MANAGE ที่วนไม่จบ (นำเสนอแบบเรียบเรียง)
- EU AI Act, Art. 15 — Accuracy, robustness & cybersecurity (in force 2024-08-01) — adversarial robustness เป็นข้อกำหนดทางกฎหมายของระบบ high-risk (อ้าง Article ไม่อ้างวันที่ deadline)
- EU AI Act, Art. 14 — Human oversight (in force 2024-08-01) — human oversight ที่มีประสิทธิผลจริงบน approval gate ตามที่บท6 อ้าง (อ้าง Article ไม่อ้างวันที่ deadline)
เช็กความเข้าใจ — บทที่ 8
ข้อ 1 / 3ในการประกอบ pipeline ของ capstone ทำไม `UseGuardrails()` ต้องห่อ *นอก* `UseFunctionInvocation()` เสมอ?