Private Docs

IMPL PLAN 04 — Authorization Flow Hardening

Hardening 6 จุดของ flow Entra → Sentinel → APIM → JWT ที่มีอยู่แล้ว: session TTL, token at-rest, realm selector, replay protection

อัปเดต: 2026-07-07

IMPL PLAN 04 — Authorization Flow Hardening (Sentinel / Session / Token)

วันที่: 07/07/2026 · สถานะ: ⏳ รอ verify · Priority: 🟡 Phase 2 อ้างอิง: DISCUSSION หมวด 4 · SG-05/06/11/22 จาก COMPLIANCE

สรุป

Flow หลัก (Entra → Sentinel cookie → APIM façade → JWT) มีครบและถูกต้องแล้ว — งานหมวดนี้คือ hardening 6 จุดของสิ่งที่มี: session TTL, token at-rest encryption, InternalOnly gate, SameSite, realm selector, replay protection


Sequence Diagram — Flow ปัจจุบัน + จุดที่ harden (ตัวเลข H1-H6)

sequenceDiagram
    autonumber
    participant B as Browser
    participant SG as Sentinel Gateway
    participant E as Entra ID / CIAM
    participant R as Redis (session store)
    participant APIM as APIM
    participant BE as Backend

    Note over B,E: ① Login (OIDC PKCE S256 — มีแล้ว)
    B->>SG: GET /sentinel/login
    SG->>E: redirect authorize (PKCE + state)
    E-->>SG: callback + code
    SG->>E: แลก code → access/refresh token
    SG->>R: เก็บ token server-side ผูก session<br/>🔧 H2: เข้ารหัส token at-rest (code มีแล้ว SG-11 — provision key + เปิด)
    SG-->>B: Set-Cookie .Exim.Auth.{tenant} (HttpOnly, Secure)<br/>🔧 H4: ทบทวน SameSite=None บน Dev/Sit/Uat (SG-22)<br/>🔧 H1: idle/absolute cap — ตั้งค่า (code มีแล้ว SG-05)

    Note over B,BE: ② เรียก API (session façade — มีแล้ว)
    B->>APIM: request + cookie
    APIM->>SG: POST /sentinel/internal/resolve-session<br/>🔧 H3: verify InternalAccess.Enabled=true ทุก env (SG-06)
    SG->>R: lookup session → token<br/>🔧 H1: เช็ค idle timeout ที่นี่
    SG-->>APIM: JWT
    APIM->>BE: forward + JWT
    BE-->>B: response

    Note over B,SG: ③ กรณีไม่มี Origin header (dual-cookie)
    B->>SG: request ไม่มี Origin
    SG->>SG: 🔧 H5: realm selector — ตอนนี้เลือก realm แรกเสมอ<br/>→ fix: เลือกจาก ?tenant= / cookie ล่าสุด

    Note over B,BE: ④ High-risk operation
    B->>APIM: POST /transfer (สมมติ)
    Note over APIM,BE: 🔧 H6: replay protection — ประเมิน nonce/idempotency key<br/>(IdempotencyFilter มีใน Package แล้ว — ใช้เป็นกลไก)

งาน H1 — Session TTL (idle + absolute cap)

สถานะ: code รองรับแล้ว (SG-05 แก้ 04/06/2026) — ค่ายังไม่ตั้งใน config ทุก env

#จุดAction
1Backend_SentinelGatewayService appsettings + IaC parity ทุก envตั้งค่า session cap — เสนอ: IdleTimeout: 30m (ผู้ใช้ทั่วไป), AbsoluteLifetime: 8h, RememberMe: idle 7d / absolute 30dตัวเลขจริง = decision D5 ของที่ประชุม
2ทดสอบ UXidle 30 นาทีบน mobile app = เด้ง login บ่อยไหม — เทสกับทีม UX ก่อน production

Verify: ปล่อย session idle เกินกำหนด → เรียก API ได้ 401 + redirect login · session อายุเกิน absolute → เหมือนกันแม้ active

งาน H2 — Token At-Rest Encryption ใน Redis

สถานะ: code มีแล้ว (SG-11) — key ยังไม่ provision

#จุดAction
1KV ทุก envprovision key: sentinel-TokenEncryption--Key (32B Base64)
2Sentinel config + IaCเปิด flag เข้ารหัส token ก่อนเขียน Redis
3Migrationsession เดิมใน Redis เป็น plaintext — เลือก: (ก) รองรับอ่านทั้ง 2 แบบชั่วคราว หรือ (ข) invalidate ทุก session ตอน deploy (user login ใหม่ — ประกาศ maintenance window)

Verify: redis-cli GET <session-key> → เห็น ciphertext ไม่เห็น token plaintext

งาน H3 — InternalOnly Gate

สถานะ: InternalOnlyAttribute default Enabled=false + ไม่พบ config ใน repo (SG-06) = อาจปิดอยู่บน env จริงโดยไม่รู้ตัว

#จุดAction
1Backend_Iac config ทุก envตรวจ/เพิ่ม InternalAccess:Enabled=true + AllowedCidrs (subnet ของ APIM) + ApiKey สำหรับ resolve-session
2Sentinel startupเพิ่ม fail-fast: ถ้า production + Enabled=false หรือ CIDR/ApiKey ว่าง → throw ตอน boot (กัน misconfig เงียบ — pattern เดียวกับ SG-19)

Verify: เรียก /sentinel/internal/resolve-session จากนอก CIDR → 403 · จาก APIM → ปกติ

งาน H4 — SameSite ต่อ env

ทบทวน SameSite=None บน Dev/Sit/Uat (SG-22) → ถ้า FE/Sentinel อยู่ same-site จริง เปลี่ยนเป็น Lax — ตรวจ cross-origin flow (LIFF/WebView) ก่อน

AuthenticationExtensions.cs:54-62 (Sentinel) เลือก realm แรกตาม DisplayOrder เสมอเมื่อไม่มี Origin → fix: รับ hint ?tenant= + fallback เป็น cookie ที่ issue ล่าสุด — เขียน unit test ครอบ 3 เคส (Origin มี / ไม่มี+tenant hint / ไม่มีทั้งคู่)

งาน H6 — Replay Protection สำหรับ High-Risk Ops

  • กลไกมีแล้ว: IdempotencyFilter + IdempotentAttribute ใน Package (UserService register แล้ว)
  • งาน: กำหนด list endpoint high-risk (write ที่มีผลเงิน/สถานะสำคัญ) → บังคับ [Idempotent] + client ส่ง Idempotency-Key header → ประเมินว่าพอสำหรับ API-GL-001 §7(2) หรือต้องเพิ่ม nonce แบบ one-time (คุยกับ compliance)

Verify รวม

  • ตาราง session TTL ต่อ env ตั้งครบ + ทดสอบ idle/absolute
  • Redis ไม่มี token plaintext
  • resolve-session ถูก gate ด้วย CIDR+ApiKey ทุก env + fail-fast ตอน boot
  • dual-cookie เลือก realm ถูกทั้ง 3 เคส
  • endpoint high-risk มี idempotency บังคับ

⚠️ ข้อควรระวัง

  1. H2 migration — เลือกทาง (ข) invalidate ต้องประกาศก่อน (ทุก user หลุด login)
  2. H3 fail-fast — ทดสอบบน dev ก่อน: ถ้า IaC ยังไม่มีค่า deploy จะ boot fail ทันที (by design แต่ต้องเตรียมค่าให้ครบก่อน merge)
  3. H1 กระทบ UX ตรงที่สุด — ให้ product owner ร่วมตัดสิน ไม่ใช่ทีม dev ตัดสินเอง

🎯 ถ้าเป็นผมจะทำอย่างไร (ความเห็น Fable)

  1. D5 ที่ผมจะเสนอ: idle 30 นาที / absolute 12 ชม. / RememberMe idle 7 วัน absolute 30 วัน — 30 วันเดิมไม่ผิดในตัวมันเองถ้ามี idle cap คู่กัน — ปัญหาคือตอนนี้ไม่มี idle cap เลย
  2. H2 migration เลือก (ข) invalidate ทุก session — dual-read เพิ่ม code path ชั่วคราวที่มักกลายเป็นถาวร · การให้ user login ใหม่ 1 ครั้งพร้อมประกาศล่วงหน้าคือราคาที่ถูกกว่ามาก — ทำนอก peak hours
  3. H3 fail-fast = ทำเลยไม่ต้องถาม — InternalOnly gate ที่อาจปิดอยู่โดยไม่รู้ตัวคือ resolve-session เปิดโล่ง = ใครก็แลก cookie เป็น JWT ได้ — นี่คืองานแรกของหมวดนี้ที่ผมจะทำ (verify ค่า env จริงก่อนอย่างอื่น)
  4. H6 อย่า over-engineer — ใช้ IdempotencyFilter ที่มี + JWT lifetime สั้น พอสำหรับ scope ปัจจุบัน (ยังไม่มี endpoint โอนเงิน) · nonce infra เต็มรูปแบบค่อยทำเมื่อมี use case จริง
  5. ลำดับของผม: H3 (เสี่ยงสุด+ถูกสุด) → H1 (ตั้ง config) → H2 (provision key) → H5 → H4 → H6 — H3 เป็น verify + fail-fast ไม่ใช่ feature ใหม่

📚 อ้างอิงมาตรฐาน (สำหรับใช้ในที่ประชุม):

หลักการแหล่งอ้างอิง
Session timeout (idle + absolute) ตามระดับ assuranceNIST SP 800-63B — Digital Identity Guidelines: Authentication & Lifecycle
Session lifecycle, cookie attributes, TTL best practicesOWASP Session Management Cheat Sheet
OAuth 2.0 security hardening (token handling, replay)RFC 9700 — Best Current Practice for OAuth 2.0 Security
SameSite + CSRF compensating controlsOWASP CSRF Prevention Cheat Sheet
Token ใน session store ฝั่ง server (BFF pattern — ยืนยัน architecture ปัจจุบันถูกทาง)IETF — OAuth 2.0 for Browser-Based Applications (draft BCP)