Private Docs

IMPL PLAN 07 — Redis Hardening

Redis คือจุดเสี่ยงสูงสุดของระบบ (ถือ session/token ทุก user) — เข้ารหัสข้อมูล, จำกัด blast radius, ตรวจ transport/access

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

IMPL PLAN 07 — Redis Hardening (Session Store + Cache)

วันที่: 07/07/2026 · สถานะ: ⏳ รอ verify · Priority: 🟡 Phase 2 อ้างอิง: DISCUSSION หมวด 7 · SG-11 + ROADMAP §3.2 (PII plaintext ใน Redis)

สรุป

Redis คือจุดรวมความเสี่ยงสูงสุดตัวเดียวของระบบ — ถือ session + token ทุก user (Sentinel) + user info cache (RedisUserInfoMiddleware ใน Package) — ถ้า Redis หลุด = hijack ได้ทั้งระบบ · งาน 4 เรื่อง: เข้ารหัสของใน Redis, ตรวจ transport/access, จำกัด blast radius, ย้าย state ที่ควรอยู่ Redis


Sequence Diagram — Data ใน Redis: ปัจจุบัน vs เป้าหมาย

sequenceDiagram
    autonumber
    participant SG as Sentinel
    participant MW as RedisUserInfoMiddleware<br/>(Backend_Package)
    participant R as Azure Redis Premium

    rect rgb(255,235,235)
    Note over SG,R: ปัจจุบัน
    SG->>R: SET session:{id} → { accessToken, refreshToken } ❌ plaintext (SG-11 code มี key ยังไม่ provision)
    MW->>R: SET userinfo:{sub} → PII (ชื่อ, email, ...) ❌ plaintext
    end

    rect rgb(235,255,235)
    Note over SG,R: เป้าหมาย
    SG->>SG: encrypt(token, AES key จาก KV) ก่อนเขียน
    SG->>R: SET session:{id} → ciphertext ✅
    MW->>MW: ลด field: เก็บเฉพาะที่ downstream ใช้จริง (minimization)
    MW->>R: SET userinfo:{sub} → เฉพาะ field จำเป็น + field อ่อนไหว encrypt ✅ + TTL สั้น
    end

งาน 7.1 — Token At-Rest Encryption (SG-11)

= งาน H2 ใน IMPL_PLAN_04 — provision key ใน KV + เปิด flag + migration plan (รองรับอ่าน 2 แบบชั่วคราว หรือ invalidate ทุก session)

งาน 7.2 — PII ใน User Info Cache

#จุดAction
1Backend_Package/src/Middleware/RedisUserInfo/UserInfoForRedis.csaudit field ทั้งหมด — ตัด field ที่ไม่มี consumer ใช้ (minimization ก่อน encryption)
2RedisUserInfoMiddleware.cs + RedisUserInfoServiceExtensions.csfield อ่อนไหวที่เหลือ (เลขบัตร ฯลฯ ถ้ามี) → encrypt ด้วย IEncryptionService ก่อน serialize
3RedisUserInfoOptions.csตรวจ TTL — cache PII ควรสั้น (เสนอ ≤ 15 นาที) ไม่ใช่ตาม session

งาน 7.3 — Transport + Access (verify จาก IaC)

Checklist ตรวจใน Backend_Iac + Azure portal (แล้ว snapshot ผลเป็นหลักฐาน):

  • TLS only: enableNonSslPort=false + client ทุกตัวต่อ port 6380 (ssl=true ใน connection string)
  • ไม่มี public endpoint — private endpoint / VNet injected เท่านั้น + firewall rules
  • AUTH ด้วย access key จาก KV (หรือ Entra ID auth ถ้า tier รองรับ) — ตรวจว่า connection string ไม่โผล่ใน manifest plaintext (ต้องมาจาก SecretProviderClass)
  • แยก Redis (หรืออย่างน้อยแยก DB index + key prefix) ระหว่าง session store ของ Sentinel กับ cache ทั่วไปของ services — จำกัด blast radius: service ธรรมดาที่ถูก compromise ไม่ควรอ่าน session ทั้งระบบได้
  • maxmemory-policy ของ session store = noeviction (session โดน evict = user หลุดแบบสุ่ม + เสี่ยง fail-open path)

งาน 7.4 — State ที่ควรอยู่ Redis (จาก in-memory)

จาก [ROADMAP §3.1 #5/M4]: ถ้าอนาคตทำ rate-limit escalation (penalty box) — state ต้องอยู่ Redis ไม่ใช่ in-memory per-pod (AKS หลาย replica = state ไม่ consistent) · Idempotency store ของ IdempotencyFilter ตรวจว่าใช้ distributed cache แล้วหรือ in-memory


Verify

  • redis-cli --scan --pattern 'session:*' + GET ตัวอย่าง → ciphertext
  • userinfo cache มีเฉพาะ field ตาม audit + TTL ≤ ค่าที่ตกลง
  • เชื่อมต่อ non-TLS ถูกปฏิเสธ · ต่อจากนอก VNet ไม่ได้
  • ตาราง “ใครต่อ Redis ไหน ด้วยสิทธิ์อะไร” เสร็จเป็นหลักฐาน

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

  1. เข้ารหัส/ลด field ใน userinfo cache = breaking change ต่อ consumer ของ middleware — ตรวจทุก service ที่อ่าน UserInfoForRedis ก่อน bump Package
  2. noeviction + memory เต็ม = write fail — ต้องมี monitoring memory + alert คู่กัน
  3. Redis Premium มี persistence (RDB/AOF) — ถ้าเปิดอยู่ ไฟล์ backup ก็มี token/PII → at-rest encryption ของ 7.1/7.2 ครอบถึง backup โดยอัตโนมัติ (เข้ารหัสก่อนเขียน) — นี่คือเหตุผลที่ encrypt ฝั่ง app ดีกว่าพึ่ง disk encryption อย่างเดียว

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

  1. 7.3 (verify transport/access) ทำก่อนเพราะเป็น read-only — ถ้าพบ Redis มี public endpoint หรือ non-SSL port เปิด นั่นคือไฟไหม้จริงที่ต้องดับก่อน encryption ทั้งหมด — ตรวจ 15 นาทีรู้ผล
  2. 7.2: minimization ก่อน encryption เสมอ — field ที่ตัดออกได้ไม่ต้อง encrypt · ผมคาดว่า audit จะพบว่า consumer ใช้จริงไม่กี่ field — เหลือน้อยจน encryption อาจไม่จำเป็นเลย
  3. การแยก session store ออกจาก cache ทั่วไป (blast radius) คือข้อที่คุ้มที่สุดในเล่มนี้ — เริ่มจาก DB index + key prefix + ACL ก่อน (ถูก) ค่อยแยก instance จริงเมื่อมีงบ — service ธรรมดาโดน compromise ไม่ควรอ่าน session ทั้งระบบได้
  4. 7.1 ทำพร้อม H2 ของ PLAN 04 เป็นงานเดียว — อย่าแยก track กันแล้วทำซ้ำ/ชนกัน
  5. ข้อ 7.4 (penalty state ใน Redis) — ยังไม่ทำ จนกว่าจะมี enforcement design จริง (ROADMAP M4) — อย่าสร้าง state ที่ไม่มี consumer

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

หลักการแหล่งอ้างอิง
Redis security model (AUTH/ACL, TLS, network isolation) — officialRedis Documentation — Security
Private endpoint / ปิด public access ของ Azure Redis (official)Microsoft Learn — Azure Cache for Redis network isolation
Session store คือ asset วิกฤต — การปกป้อง session dataOWASP Session Management Cheat Sheet
ทำไม token/PII at-rest ต้องเข้ารหัสแม้อยู่หลัง firewallOWASP A02
— Cryptographic Failures