บทที่ 26 · Part 6 — Advanced Security Engineering
Advanced Attacks & Software Supply Chain
SSRF, parser differentials, request smuggling, cache poisoning, deserialization, race conditions, SBOM, provenance, signing และ fuzzing
advanced attack มักไม่ชนะ control ตรงๆ แต่ใช้ความไม่สอดคล้องระหว่างหลายชั้น เช่น proxy กับ origin parse request ไม่เหมือนกัน, validator ตรวจ URL ก่อน DNS เปลี่ยนคำตอบ หรือ deployment ตรวจ signature แต่ไม่ผูก signer กับ policy บทนี้เน้นช่องว่างระหว่าง component และระหว่าง build ถึง runtime
Learning Outcomes
- ป้องกัน SSRF ด้วย destination validation, isolation และ egress controls หลายชั้นได้
- อธิบาย request smuggling/cache poisoning จาก parser และ cache-key disagreement ได้
- enforce race/TOCTOU invariant ที่ storage/state boundary ได้
- สร้าง software supply-chain controls ตั้งแต่ source, dependency, build, registry ถึง deploy ได้
- แยก SBOM, provenance, signature และ vulnerability scan ตามหลักฐานที่แต่ละอย่างให้ได้
- วาง fuzzing/property tests สำหรับ parser, protocol และ state machine ได้
Advanced หมายถึง Compositional Risk
ระบบแต่ละชิ้นอาจปลอดภัยเมื่อมองเดี่ยว แต่ composition สร้างช่องว่าง:
- CDN normalize path แบบหนึ่ง แต่ origin ใช้อีกแบบ
- WAF inspect header 1 ชุด แต่ proxy forward อีกชุด
- authorization check object version A ก่อน worker แก้ object version B
- CI sign artifact ที่ build จาก source/reference ซึ่งเปลี่ยนได้
- runtime ใช้ image tag ที่ไม่ใช่ digest ที่ security gate ตรวจ
threat model จึงต้องบันทึก parser, canonical form, trust transfer และ time-of-check/time-of-use ทุก boundary
Server-Side Request Forgery
SSRF เกิดเมื่อ attacker ทำให้ server ส่ง request ไป destination ที่ attacker เลือกหรือมีอิทธิพล ผลกระทบอาจเป็น:
- อ่าน cloud metadata/credential
- เข้าถึง internal admin/control plane
- scan private network
- ข้าม source-IP allowlist
- ส่ง request ด้วย service identity
- exfiltrate ผ่าน callback
- ใช้ server เป็น proxy ในการโจมตีภายนอก
features ที่พบบ่อย ได้แก่ webhook tester, URL preview, image/PDF importer, document converter, SSO metadata, server-side browser และ partner callback
SSRF Defense by Design
Case 1: Destination ที่ทราบล่วงหน้า
ใช้ allowlist ของ scheme, exact host, port และ path family ที่จำเป็น แล้วสร้าง destination จาก trusted configuration มากกว่ารับ full URL จาก input
Case 2: Destination แบบ Arbitrary URL
กรณี business ต้อง fetch URL ทั่วไปควรแยก isolated fetcher ที่:
- ไม่มี cloud/workload credential
- ไม่มี route ไป private/control-plane network
- จำกัด egress protocol/port/destination category
- มี DNS resolver/policy ที่ควบคุม
- cap connect/read/total timeout
- cap redirect count และ revalidate ทุก redirect
- cap response size/decompression/content type
- ไม่ forward inbound credential/header/cookie
- return sanitized content ไม่ใช่ raw trusted response
application หลักส่ง job ที่มีขอบเขตไป fetcher ไม่ควรเปิด generic proxy API
URL Validation Is Not Enough
validation ต้องระวัง:
- alternate IP notation, IPv4-in-IPv6 และ encoded forms
- userinfo (
user@host) และ parser disagreement - trailing dot, case, Unicode/IDNA และ ambiguous hostname
- DNS rebinding หรือ answer เปลี่ยนระหว่าง check/connect
- CNAME/redirect ไป private/link-local/loopback
- unsupported scheme เช่น
file,gopherหรือ protocol handler ภายใน - redirect ที่เปลี่ยน scheme/host/port
- HTTP client proxy/environment behavior
แนวทางที่แข็งแรงคือ parse ด้วย library เดียวกับ client, canonicalize, resolve, ตรวจทุก resolved IP กับ policy, connect ไป address ที่ตรวจแล้วและยืนยัน host/TLS identity พร้อม revalidate redirect/retry
Blocklist Private IP อย่างเดียวไม่ใช่ SSRF Defense สมบูรณ์
address range/service endpoint เปลี่ยนได้และมี non-IP path อื่น ต้องใช้ allowlist เมื่อทำได้, isolation, least-privilege workload identity, metadata hardening และ network egress ร่วมกัน
Cloud Metadata Defense
บน AWS ควร require IMDSv2 เมื่อ workload compatible และจำกัด metadata access/hop ตาม architecture แต่ IMDSv2 ไม่แก้ SSRF root cause และ process ที่รันบน instance อาจยังขอ token/credential ได้
defense เพิ่ม:
- instance role แบบ least privilege
- container/host network rule จำกัด IMDS
- ไม่ให้ URL fetcher อยู่บน credentialed workload
- detect metadata destination attempts
- short session และ credential-incident runbook
Request Smuggling
HTTP request smuggling เกิดเมื่อ front-end กับ back-end ไม่เห็น request boundary เหมือนกัน ตัวอย่างสาเหตุ:
Content-LengthกับTransfer-Encodingambiguity- duplicate/conflicting headers
- HTTP/2 หรือ HTTP/3 translation ลง HTTP/1.1
- whitespace/case/obs-fold parsing ต่างกัน
- proxy chain reuse connection แต่ตีความ body length ไม่ตรง
ผลคือ bytes ที่ hop แรกคิดว่าเป็น body อาจกลายเป็น request ใหม่ที่ origin ทำให้ bypass security control, poison response queue, hijack request context หรือเข้าถึง internal route
Defense
- patch/load balancer/proxy/server ให้เป็น supported current versions
- ลดจำนวน protocol translations และ intermediaries
- reject malformed/ambiguous framing แทนการ normalize เงียบ
- ใช้ consistent end-to-end protocol เมื่อทำได้
- ปิด connection เมื่อ parse error
- test edge-to-origin chain จริง ไม่ test component เดี่ยว
- monitor framing errors, 4xx anomalies และ response desynchronization
regex ที่ WAF ชั้นเดียวไม่แก้ parser differential ใน hop ถัดไป
Cache Poisoning and Cache Deception
cache key กำหนดว่า request ใด share response หาก origin ใช้ input ที่ cache ไม่รวมใน key attacker อาจทำให้ response อันตรายถูกเก็บและเสิร์ฟให้ผู้อื่น
ตรวจ:
Host, forwarded host/proto และ absolute URL construction- unkeyed query/header/cookie
- content negotiation, locale, encoding และ device variants
- authorization/session/tenant context
- path normalization, extension และ semicolon/delimiter
- error/redirect caching
Vary,Cache-Controlและ surrogate controls
private/personal response ต้องไม่เข้า shared cache และ cache key ต้องรวมทุก dimension ที่เปลี่ยน response อย่าง ปลอดภัย การใส่ทุก header ลง key อาจสร้าง cache fragmentation/DoS จึงต้องกำหนด contract ชัด
Cache Deception
attacker สร้าง URL ที่ดูเป็น static asset ต่อ cache แต่ application route ยังตอบข้อมูลส่วนบุคคล เช่นเติม extension หรือ path segment ที่ origin ignore ป้องกันด้วย route normalization ที่สอดคล้อง, deny ambiguous path และ cache เฉพาะ known-static responses ที่มี explicit policy
Canonicalization Boundary
signature, cache, authorization, routing และ logging ต้องเห็น representation เดียวกัน:
- method และ normalized path
- query ordering/duplicate semantics
- header names/values
- body bytes/content encoding
- Unicode normalization
- numeric/date representation
อย่า canonicalize หลัง security check แล้วส่ง representation ใหม่ downstream เพราะ attacker อาจสร้าง 2 input ที่ control เห็นเท่ากันแต่ business logic เห็นต่าง หรือกลับกัน
Unsafe Deserialization
deserialization ของ untrusted data อาจเรียก gadget, instantiate type, allocate resource หรือเปลี่ยน object state โดยไม่ผ่าน invariant
defense:
- ใช้ simple data format/schema แทน native object serialization
- allowlist concrete message types/fields
- strict schema, size, depth, count และ recursion limits
- reject unknown/duplicate fields ตาม contract ที่เลือก
- แยก parsing จาก side effect
- ห้ามใช้ type metadata/class name จาก input เพื่อ instantiate arbitrary code
- patch serialization library และ remove dangerous gadget dependencies
- authenticate message แต่ยัง validate semantics หลัง signature
signature บอกว่า message มาจาก key ที่เชื่อถือได้ ไม่ได้ทำให้ payload ปลอดภัยต่อ parser หรือ business logic
Parser and Decompression Bombs
small input อาจขยายเป็น memory/CPU/disk จำนวนมาก เช่น archive/XML/entity/image/regex/compressed body
กำหนด:
- compressed และ decompressed size
- nesting/depth/file count
- CPU/wall-clock timeout
- memory/disk quota
- recursion/regex complexity
- streaming parser/backpressure
- isolated worker และ concurrency cap
ตรวจ limit ทุก hop เพราะ edge อาจวัด compressed bytes ขณะที่ application allocate decompressed bytes
Race Conditions and TOCTOU
Time-of-check/time-of-use เกิดเมื่อ state เปลี่ยนระหว่างตรวจและใช้:
Request A: read balance_satang = 10000 -> validate debit 8000 -> wait -> write 2000
Request B: read balance_satang = 10000 -> validate debit 8000 -> wait -> write 2000
ทั้ง 2 request อาจผ่าน check แม้ยอดรวมถูก debit 16000 สตางค์ ตัวอย่างนี้ไม่ได้แก้ด้วย idempotency key ต่างกัน เพราะเป็น business concurrency ไม่ใช่ duplicate retry
Enforce Invariant at the Boundary
กลไกที่ใช้ได้ตาม data model:
- atomic conditional update
- database transaction และ appropriate isolation
- unique constraint
- row/advisory lock
- compare-and-swap/version column
- append-only ledger พร้อม balancing invariant
- serialized state machine/partitioned queue
mutex ใน process เดียวไม่พอเมื่อมีหลาย instance, retry หรือ worker restart
Test Concurrently
- ยิง request พร้อมกันด้วย barrier
- vary ordering/delay/failure/retry
- assert invariant หลังทุก execution
- รันกับ database/isolation จริง
- เก็บ regression test จาก incident
- fuzz state-machine command sequence
test แบบ sequential อาจผ่านตลอดแต่ไม่แตะ race window
Software Supply Chain Threat Model
artifact ที่ deploy ได้รับอิทธิพลจาก:
- developer/maintainer identity
- source repository/branch protection
- dependency registry/resolver
- CI runner/plugin/action
- build image/toolchain
- secret/token/OIDC trust
- artifact registry/tag
- deployment controller/policy
- runtime updater
attacker ไม่ต้องแก้ source application หากขโมย publish token, poison dependency หรือเปลี่ยน mutable tag ได้
Source and Review Controls
- phishing-resistant MFA สำหรับ maintainer/administrator
- least-privilege repository roles
- protected branch/tag และ required review
- signed/verified commit หรือ tag เมื่อ policy ต้องการ
- review CODEOWNERS/security-sensitive files
- alert force push, branch-rule และ deploy-key changes
- separate human/admin/bot identities
- short-lived CI identity ผ่าน trusted OIDC claims
review 2 คนไม่ช่วย หากทั้งคู่เห็น generated/minified change ที่ตรวจไม่ได้หรือ CI build จาก source คนละ revision
Dependency Security
- lock exact resolved versions และ integrity hashes เมื่อ ecosystem รองรับ
- ใช้ trusted registry/proxy และ namespace ownership
- ป้องกัน dependency confusion ด้วย scope/source rules
- minimize dependency และ transitive surface
- run SCA/license/malware/reputation checks เป็น signal
- update แบบต่อเนื่องพร้อม test แทน freeze ถาวร
- maintain vulnerability/remediation/exception process
- inventory build/test dependencies ไม่เฉพาะ runtime
version pin ลด surprise แต่เก็บ vulnerability ไว้ได้ จึงต้องมี controlled update loop
Build Isolation
build environment ควร:
- ephemeral และเริ่มจาก trusted immutable image
- จำกัด network egress
- ไม่มี credential เกิน step ที่ต้องใช้
- แยก untrusted pull-request build จาก release secret
- pin CI actions/plugins/images ด้วย immutable reference
- record source digest, dependency, command, builder identity และ environment
- produce artifact once แล้ว promote digest เดิม
- prevent post-build mutation
การ rebuild แยกทุก environment สร้าง artifact ต่างกันและขยายจุดที่ supply chain ถูกแทรกได้
SBOM, Provenance, Signature and Scan
| Evidence/control | ตอบคำถาม | ไม่ได้พิสูจน์ |
|---|---|---|
| SBOM | artifact มี component ใด | component ปลอดช่องโหว่/ไม่ malicious |
| Provenance | artifact ถูก build ที่ไหน อย่างไร จาก input ใด | source ปลอดภัยหรือ review ถูกต้อง |
| Signature | key/identity ใดรับรอง bytes/digest นี้ | signer หรือ artifact สุจริต |
| Vulnerability scan | scanner รู้จัก finding ใดใน coverage นี้ | ไม่มี unknown/logical vulnerability |
| Reproducible build | independent build ให้ bytes ตรงกัน | source intent ปลอดภัย |
ต้อง compose หลักฐานและ enforce policy ที่ deploy ไม่ใช่เพียงเก็บไฟล์ไว้ข้าง artifact
SLSA Provenance
SLSA provenance ให้ verifiable information ว่า artifact ถูกสร้างเมื่อไร ที่ไหน อย่างไร และจาก inputs ใด ช่วยตรวจ build/source linkage และ builder controls ตามระดับ/requirements ที่ใช้
provenance ไม่ได้พิสูจน์ว่า source ไม่มี backdoor, dependency ปลอดภัย หรือ reviewer ตัดสินถูก จึงต้องใช้คู่กับ source governance, dependency controls, testing และ deployment policy
Artifact Signing
signature มีผลเมื่อ verifier ตรวจ:
- artifact digest ที่จะรันจริง
- signature cryptography
- signer identity/issuer
- repository/workflow/environment claims
- certificate/transparency proof/validity ตาม scheme
- policy เช่น release branch, builder และ approval
- revocation/incident state
การ verify ว่า “มีลายเซ็นใดก็ได้” เปิดให้ untrusted signer รับรอง artifact ได้ และการ verify tag แทน digest เสี่ยง mutable reference เปลี่ยนหลัง gate
Sigstore
Sigstore keyless signing ใช้ ephemeral signing key ผูกกับ OIDC identity ผ่าน certificate และ transparency log ช่วยลด long-lived signing-key management บางส่วน
verifier ยังต้อง pin:
- trusted OIDC issuer
- expected identity/repository/workflow
- artifact digest
- transparency/inclusion requirements
- certificate/claim time semantics
หาก IdP, maintainer หรือ trusted build workflow ถูก compromise attacker อาจสร้างลายเซ็นที่ valid ได้ Signature จึงเป็น provenance/authenticity evidence ไม่ใช่ malware detector
Deployment Admission
ก่อน production deploy ให้ policy engine/controller ตรวจ:
- immutable digest อยู่ใน approved registry
- signature/provenance ตรง trusted builder/source
- SBOM/scan policy ผ่านหรือมี time-bound exception
- artifact อายุ/version/environment ตรง release
- deployment identity มี scope เฉพาะ target
- configuration/IaC ผ่าน review/policy tests
ควรบันทึก decision/evidence และป้องกัน privileged user bypass admission โดยไม่มี break-glass audit
Vulnerability Management
scanner finding ต้องผ่าน lifecycle:
- normalize/deduplicate
- ตรวจ exploitability, exposure, asset/data และ compensating controls
- assign owner/SLA
- patch, upgrade, remove หรือ mitigate
- test/deploy
- verify finding/control
- time-bound exception พร้อม residual-risk owner
CVSS อย่างเดียวไม่สะท้อน business exposure และ “ไม่มี fix” ไม่ได้แปลว่ายอมรับ risk โดยอัตโนมัติ
Fuzzing
fuzzing สร้าง input/sequence จำนวนมากเพื่อหา crash, hang, memory error หรือ invariant violation เหมาะกับ:
- URL/HTTP/message parsers
- file/archive/image/document formats
- signature/canonicalization
- protocol/state machine
- authorization policy evaluator
- transaction/ledger command sequence
fuzzer ที่ดีต้องมี:
- representative seed corpus
- mutation strategy/grammar เมื่อจำเป็น
- coverage/sanitizer/runtime checks
- oracle เช่น never panic, balance conserved, deny unknown tenant
- resource limits และ reproducibility
- crash triage/minimization
- regression test หลังแก้
fuzzing ไม่แทน threat model หรือ semantic authorization test เพราะ “ไม่ crash” ไม่แปลว่า “ไม่อนุญาตผิด”
Adversarial Verification
advanced security program ควรรวม:
- architecture/threat-model review
- code review และ static analysis
- dependency/image/IaC scanning
- integration/negative/concurrency/property tests
- DAST/API/mobile testing
- fuzzing
- penetration test/red/purple-team exercise ตาม risk
- detection/containment game day
finding ต้องย้อนกลับเป็น regression test, control improvement หรือ explicit risk decision
Review Checklist
- URL fetch ใช้ allowlist เมื่อทำได้ หรือ isolated credentialless fetcher + egress policy
- resolved IP/redirect/retry ทุกครั้งผ่าน destination policy และ resource limits
- proxy/origin reject ambiguous HTTP framing และทดสอบ protocol translation end-to-end
- cache key/normalization ครอบคลุม tenant/auth/content dimensions
- parser มี schema, type, depth, size, time และ decompression limits
- race invariant enforce ที่ durable state boundary และมี concurrent tests
- repository/CI/registry/deploy identities short-lived/scoped/monitored
- dependency lock/integrity/source/update/exception lifecycle ครบ
- build isolated และ produce-once/promote-by-digest
- SBOM/provenance/signature/scan ไม่ถูกสรุปเกินหลักฐานที่ให้
- deploy verify digest, signer/issuer/claims/provenance และ policy จริง
- fuzz target มี corpus, oracle, resource limit, triage และ regression
สรุป
advanced attack ใช้ความไม่สอดคล้องระหว่าง parser, policy, identity, cache และเวลา Defense ต้องกำหนด canonical boundary, enforce invariant ที่ปลายทาง และลด trust transfer ใน software supply chain SBOM, provenance, signature และ scan ให้หลักฐานคนละชนิด จึงต้อง verify ร่วมกันที่ deployment boundary