บทที่ 15 · Part 3 — API & Mobile Security
API Abuse & Transaction Integrity
Rate/cost limits, replay defense, request/webhook signing, idempotency, race/TOCTOU, double spend และ transaction-data binding
API อาจไม่มีช่องโหว่ทาง syntax และทุก request ผ่าน authentication แต่ผู้ใช้ที่มีสิทธิ์อาจเรียก promotion endpoint 10,000 ครั้ง, ส่ง withdrawal พร้อมกันหลาย connection หรือ replay callback ที่ลงนามถูกต้องจนระบบจ่ายเงินซ้ำ ช่องโหว่เหล่านี้อยู่ที่ business flow, freshness และ state invariant
Learning Outcomes
- ออกแบบ rate/cost/concurrency limit หลายมิติได้
- แยก request authentication, replay defense และ idempotency ได้
- verify webhook/signature พร้อม timestamp/nonce/event state ได้
- ผูก authorization proof กับ transaction detail/version ได้
- ป้องกัน race, TOCTOU และ double spend ที่ storage/state boundary ได้
- แยก Security enforcement จาก fraud/risk policy ที่ต้องมี human owner ได้
Abuse ไม่จำเป็นต้อง Exploit Code
ตัวอย่าง business-flow abuse:
- signup หลาย account รับ incentive ซ้ำ
- OTP/card testing สร้างต้นทุนและใช้ตรวจ credential
- scrape exchange rate หรือ account existence
- แบ่ง transfer/refund เพื่อหลบ threshold
- reserve resource แล้วไม่ complete
- ส่ง callback/request เดิมซ้ำ
- เรียก operation พร้อมกันก่อน state update
API6:2023 เรียกความเสี่ยงนี้ว่า Unrestricted Access to Sensitive Business Flows
Rate Limit ต้องมีหลาย Dimension
| Dimension | ป้องกัน/จำกัด |
|---|---|
| Subject/account | abuse ต่อ identity |
| Credential/client | compromised integration |
| IP/network/ASN | traffic source แต่ไม่ใช้เป็น identity |
| Device/installation | distributed account abuse บางรูปแบบ |
| Tenant/merchant | noisy neighbor และ contractual quota |
| Endpoint/operation | expensive/sensitive action |
| Business object | OTP recipient, card, beneficiary, promotion |
| Global/downstream | system/provider capacity และ cost |
limit ควรรวม request rate, burst, concurrency, bytes, query cost และ monetary/vendor cost พร้อม response ที่ไม่ทำให้ client retry storm
Account Lockout ถูกใช้ทำ DoS ได้
attacker อาจจงใจชน limit ของ victim การเลือก block, delay, challenge, step-up หรือ review ต้องพิจารณาผลกระทบต่อผู้ใช้จริงและมี fraud/risk owner
Rate Limit ไม่หยุด Distributed Abuse ทั้งหมด
botnet กระจาย IP, account และ device ได้ ขณะที่ผู้ใช้จริงจำนวนมากอาจอยู่หลัง NAT เดียว จึงต้องรวม velocity/relationship/behavior, compromised credential, device signal, cost budget และ detection โดยมี privacy/retention policy
ระบบต้องตัดสินใจเมื่อ limiter unavailable ด้วย: fail open อาจเกิด loss; fail closed อาจหยุดบริการ degraded limit และระยะเวลาต้องออกแบบ/ทดสอบล่วงหน้า
แยก 3 Concept สำคัญ
| Concept | คำถาม |
|---|---|
| Authentication/integrity | request มาจาก identity/key ที่เชื่อถือและไม่ถูกแก้หรือไม่ |
| Freshness/replay defense | request นี้ใหม่และอยู่ใน acceptance window หรือไม่ |
| Idempotency | การประมวลผล logical operation ซ้ำให้ผลเดียวเดิมหรือไม่ |
signature ที่ valid อาจถูก replay; nonce/timestamp ที่ใหม่ยังไม่ authorize resource; idempotency key ที่ไม่ authenticate caller อาจถูกเดาหรือชนกัน ทุกชั้นต้องผูก context เดียวกัน
Request Signing ต้องใช้ Protocol ที่ชัด
RFC 9421 HTTP Message Signatures กำหนด canonicalization และ covered components สำหรับ HTTP การออกแบบต้องระบุ:
- algorithm/key ID และ key lifecycle
- request components ที่ sign: method, target URI, authority, selected headers
- content digest/body binding เมื่อ operation ต้องปกป้อง body
- creation/expiry time และ nonce
- audience/environment/partner context
- server-side replay state/window
- proxy transformations ที่ยอมรับ
ห้ามสร้าง concatenate(method + path + body) protocol เองโดยไม่มี canonicalization/versioning review
และ signature ไม่แทน TLS หรือ resource authorization
DPoP ไม่ใช่ Transaction Signing
DPoP ผูก proof กับ key, method, URI และ access token hash ตาม protocol แต่ไม่ได้ sign amount, beneficiary หรือ request body/headers ส่วนใหญ่ High-value operation ต้องมี transaction-data binding หรือ message signature เพิ่มตาม profile
Webhook Verification
webhook เป็น Internet-facing state transition ไม่ใช่ “trusted callback”:
- จำกัด request bytes/content type ก่อนงานแพง
- อ่าน raw bytes ตาม provider signing specification
- เลือก key/algorithm จาก trusted configuration/key ID policy
- verify signature แบบ constant-time/library ที่เหมาะสม
- ตรวจ timestamp/expiry และ environment/destination
- ตรวจ event ID/replay uniqueness
- parse schema และ authorize provider/event type
- apply state transition แบบ idempotent/atomic
- เก็บ result แล้วตอบ retry-safe status
อย่า parse JSON แล้ว reserialize ก่อน verify ถ้า provider sign raw bytes และอย่า log signature/secret/payload ละเอียดโดยไม่มี data policy
Idempotency Key Design
Idempotency-Key เป็น API convention; ณ baseline นี้ยังไม่มี RFC final ที่กำหนด semantics สากล contract ต้องบอก scope, retention, conflict และ concurrent behavior เอง
bind key กับ:
principal/client + operation + resource/tenant + canonical request hash
state ที่ต้องเก็บ:
| Field | Purpose |
|---|---|
| Scope + key | uniqueness boundary |
| Request hash | reject key reuse กับ payload ต่าง |
| Status | processing / succeeded / failed-final |
| Outcome reference | ส่ง response เดิมโดยไม่ทำ side effect ซ้ำ |
| Created/expiry | retry contract และ storage lifecycle |
Atomic Claim
INSERT INTO idempotency_records
(principal_id, operation, idempotency_key, request_hash, status)
VALUES ($1, $2, $3, $4, 'PROCESSING')
ON CONFLICT DO NOTHING;
หลัง insert ต้องแยกกรณี:
- record ใหม่ → process
- key เดิม + hash เดิม + success → คืน outcome เดิม
- key เดิม + hash ต่าง → conflict/reject
- key เดิม + processing → wait/poll/conflict ตาม contract
- stale processing → recover ด้วย state machine ไม่ทำ side effect แบบเดาสุ่ม
claim, state transition และ financial side effect ต้องออกแบบ atomic/transactional ให้เหมาะกับระบบ
Idempotency ไม่เท่ากับ Exactly Once
network อาจส่งซ้ำและ process อาจตายระหว่าง external side effect กับการบันทึกผล external provider ต้องรองรับ idempotency/reference/query status หรือมี reconciliation/compensation
Transaction Authorization: What Is Approved
proof/approval ต้องผูกกับรายละเอียดที่มีผล:
- operation และ source account
- amount/currency/fee/rate
- beneficiary/destination
- schedule/time window
- transaction ID/version
- policy/assurance context ตาม profile
ถ้าค่าใดเปลี่ยน approval เดิมต้อง invalid และก่อน execute ต้อง recheck current authorization/state เพื่อกัน TOCTOU
approved_transaction_hash = HASH(canonical_transaction_details)
canonical format/version ต้องกำหนดชัดและ hash ไม่แทน signature/authorization หาก attacker แก้ทั้ง data และ hash ได้
Race Condition และ TOCTOU
รูปแบบผิด:
1. SELECT balance = 100000
2. if balance >= 80000: allow
3. concurrent request ทำเหมือนกัน
4. ทั้ง 2 UPDATE balance - 80000
mutex ใน process เดียวไม่พอเมื่อมีหลาย instance ใช้ database transaction, conditional update, unique constraint, locking/serialization หรือ atomic state machine ตาม invariant
ตัวอย่าง conditional update:
UPDATE wallet_balances
SET available_satang = available_satang - $1,
version = version + 1
WHERE wallet_id = $2
AND available_satang >= $1
AND version = $3;
success ต้องตรวจ affected rows และ ledger ที่เป็นเงินจริงควรใช้ double-entry/append-only invariant ไม่ใช้ balance column เดียวเป็นบัญชีสุดท้าย
Double Spend ต้องป้องกันที่ State Boundary
control หลายชั้น:
- idempotency ต่อ logical request
- unique provider/transaction reference
- atomic reserve/post state transition
- ledger constraints และ balance invariant
- concurrency test หลาย instance
- reconciliation กับ external system
- anomaly detection และ bounded manual correction
API gateway rate limit ลด load แต่ไม่รักษา ledger invariant และ request signature ไม่หยุด valid request 2 รายการที่ใช้ balance เดียวกัน
Retry และ Exceptional Conditions
contract ต้องระบุว่า error ใด retry ได้, client ใช้ key เดิมหรือใหม่, response timeout หมายถึงอะไร และ query status ได้หรือไม่
| Failure | Safe Design Question |
|---|---|
| timeout ก่อน response | side effect เกิดแล้วหรือยัง และ lookup ด้วย reference ได้ไหม |
| worker ตายหลัง provider call | result ถูก recover/reconcile อย่างไร |
| duplicate callback | unique event/state transition อยู่ที่ใด |
| limiter/policy store ล่ม | degraded behavior และ duration คืออะไร |
| partial dependency failure | transaction ค้าง state ใดและใคร resolve |
Security กับ Fraud Decision
Threshold ที่กระทบเงินต้องมี Human Owner
Security engineering สร้าง identity, integrity, limits, telemetry, policy enforcement และ safe state แต่ threshold เช่นวงเงิน, velocity, account hold, device risk และ manual review มี customer/financial impact ต้องถูกกำหนดโดย Product, Fraud/Risk, Operations, Security และ Compliance ที่มีอำนาจ
code ต้อง version/audit policy และบอก evidence ไม่ hardcode ค่าจากตัวอย่างหรือให้ model ตัดสินโดยไม่มี human governance/appeal path
Testing Checklist
- limits ครอบคลุม principal/IP/device/tenant/object/global/cost/concurrency
- limiter failure มี degraded behavior ที่ทดสอบแล้ว
- authentication, replay defense และ idempotency แยกหน้าที่ชัด
- request signature ครอบ covered components/context และมี replay state
- webhook verify raw/canonical input ตาม spec + event uniqueness
- idempotency bind caller/operation/request hash และ atomic claim/outcome
- approval bind amount/currency/beneficiary/version และ invalid เมื่อข้อมูลเปลี่ยน
- race/double-spend tests รันพร้อมกันข้ามหลาย instance
- storage enforce invariant ด้วย transaction/constraint/state machine
- fraud/risk threshold มี human owner, version, audit และ exception
สรุป
Transaction integrity ต้องต่อหลาย control: authenticate request, bind context, ตรวจ freshness, ทำ idempotency และ enforce invariant ที่ state boundary Rate limit ลด abuse/cost แต่ไม่แทน authorization, replay defense หรือ atomic ledger design