01204223/secrets

จาก Theory Wiki
รุ่นแก้ไขเมื่อ 15:59, 26 กุมภาพันธ์ 2569 โดย Jittat (คุย | มีส่วนร่วม) (สร้างหน้าด้วย "เราจะฝึกจัดการกับข้อมูลที่เป็นความลับในการพัฒนาเว็บ...")
(ต่าง) ←รุ่นแก้ไขก่อนหน้า | รุ่นแก้ไขล่าสุด (ต่าง) | รุ่นแก้ไขถัดไป→ (ต่าง)
ไปยังการนำทาง ไปยังการค้นหา

เราจะฝึกจัดการกับข้อมูลที่เป็นความลับในการพัฒนาเว็บแอพ

เนื้อหา

แนวปฏิบัติทั่วไปในการจัดการ secrets (รหัสผ่าน / API keys) สำหรับเว็บแอป Flask + React

เขียนโดย chatgpt

หลักคิดพื้นฐาน

ห้ามฝัง secret ลงในโค้ด (รวมถึง commit เข้า git, paste ลง issue, หรือส่งในแชต)

ให้สิทธิ์เท่าที่จำเป็น (least privilege) เช่น key ที่ใช้เรียก API แค่ read ก็อย่าให้ write

แยกสภาพแวดล้อม (dev / staging / prod) และใช้ secret คนละชุดเสมอ

หมุนคีย์ได้ (rotation) ออกแบบให้เปลี่ยน key/รหัสผ่านแล้วระบบรันต่อได้ ไม่ต้อง deploy แบบเสี่ยง ๆ

ทุกอย่างที่อยู่ฝั่ง client ถือว่า “เปิดเผยได้” เพราะ React build แล้วผู้ใช้สามารถดูไฟล์ JS ได้

ทำความเข้าใจ “อะไรเป็น secret” ในสถาปัตยกรรม Flask + React

อะไรที่ควรอยู่ฝั่ง Backend (Flask) เท่านั้น

รหัสผ่าน DB, connection string

API key ของบริการภายนอกที่มีสิทธิ์ “ทำอะไรได้จริง” (เช่น จ่ายเงิน, ส่งอีเมล, อ่านข้อมูลส่วนตัว)

JWT signing key / session secret / Flask SECRET_KEY

Private keys (เช่น OAuth client secret, service account key)

อะไรที่ “ไม่ใช่ secret” และอยู่ฝั่ง Frontend ได้

ค่า config ที่เป็น public เช่น base URL, feature flag บางชนิด, public analytics key (ที่ผู้ให้บริการออกแบบให้เปิดเผยได้)

OAuth client id มักไม่ถือเป็น secret (แต่ client secret เป็น secret)

Git และการป้องกันการหลุดเข้าระบบควบคุมเวอร์ชัน

ใส่ไฟล์ secret ใน .gitignore เช่น

    • .env
    • config.local.json
    • .pem, .key

ใช้ pre-commit hook หรือเครื่องมือสแกน secret เพื่อกันพลาด (เช่นตรวจพบ pattern ของ key ก่อน commit)

ถ้าเผลอ commit ไปแล้ว:

    • ถือว่า secret “รั่ว” แล้ว (แม้จะ revert ก็ยังอยู่ใน history)
    • รีบ revoke/rotate key
    • พิจารณา rewrite history (แต่ต้องเข้าใจผลกระทบกับทีม)

การเก็บ secret ระหว่าง Development

ใช้ Environment Variables

แนวทางที่พบบ่อยสุดคือเก็บ secret ใน environment variables แล้วให้ Flask อ่านจาก env

ข้อดี: ไม่ต้องใส่ลงโค้ด, แยก env ได้ง่าย

ข้อควรระวัง: อย่า log ค่า env ออกมา, และอย่าให้ dump env ใน error page

ใช้ไฟล์ .env ในเครื่องตัวเอง (dev only)

ใช้ .env สำหรับ dev และใส่ลง .gitignore

ทำไฟล์ตัวอย่าง (.env.example) ที่ไม่มี secret จริง เช่น

    • DATABASE_URL=postgresql://USER:PASSWORD@HOST/DB (ใส่ placeholder)
    • STRIPE_SECRET_KEY=... (placeholder)

การเก็บ secret ใน Production

ใช้ Secret Manager ของแพลตฟอร์ม

แนวปฏิบัติทั่วไป:

Docker/Kubernetes: ใช้ Kubernetes Secrets + mount เป็น env หรือไฟล์

Cloud: ใช้ secret manager (เช่น AWS/GCP/Azure) แล้วดึงตอนรัน

PaaS: ตั้งค่า secret ผ่าน dashboard/CLI (เช่น environment config ของ platform)

หลักสำคัญ:

จำกัดสิทธิ์การเข้าถึง secret manager ให้เฉพาะ service account ของแอป

audit log ได้ว่าใคร/อะไรเข้าถึง secret

หลีกเลี่ยงการวาง secret ไว้ใน image/build artifact

อย่า bake secret เข้า Docker image

อย่าให้ขั้นตอน build ของ React รับ secret จริง (เพราะจะถูก bundle ลงไฟล์ JS)

Flask: จุดที่เกี่ยวกับ secret โดยตรง

Flask SECRET_KEY และ session security

ตั้งค่า SECRET_KEY จาก env

ห้ามใช้ค่าเดิมระหว่างหลาย environment

หมุนคีย์แล้วกระทบ session (ผู้ใช้อาจถูก logout) — ถือเป็นเรื่องปกติ

Database credentials / connection string

อ่านจาก env เช่น DATABASE_URL

ให้ DB user มีสิทธิ์เท่าที่ต้องใช้ (แยก read/write ถ้าทำได้)

JWT / OAuth / API signing keys

เก็บ private/signing key ฝั่ง backend เท่านั้น

แยก key ต่อ environment

พิจารณาใช้ key id (kid) เพื่อรองรับ rotation หลายคีย์พร้อมกัน

React: สิ่งที่ต้องระวังเป็นพิเศษ

ทุกอย่างที่อยู่ใน React build “ไม่ลับ”

ค่าใน process.env ที่ถูก inject ตอน build จะไปอยู่ใน bundle

ต่อให้ obfuscate ก็ยังดึงได้

ถ้าต้องเรียกบริการภายนอก ให้ทำผ่าน Backend เป็น proxy

ตัวอย่างสถานการณ์:

React ต้องเรียก API ที่ต้องใช้ secret → ให้ React เรียก Flask ก่อน แล้ว Flask ใส่ secret เรียกต่อ

จะได้ควบคุม:

    • rate limit
    • validation
    • logging/audit
    • permission ตาม user

การตั้งค่าฝั่ง frontend แบบปลอดภัย

เก็บเฉพาะ public config เช่น REACT_APP_API_BASE_URL

ถ้าต้องการ runtime config ให้เสิร์ฟไฟล์ config จาก backend (ที่ไม่มี secret) แทนการ bake ตอน build

การส่ง secret ระหว่างบริการ (backend ↔ external services)

ใช้ HTTPS เสมอ

ตั้ง timeout และ retry policy (ลดโอกาสหลุด log แปลก ๆ)

อย่าใส่ secret ใน query string (URL) เพราะอาจหลุดใน:

    • server access logs
    • browser history
    • referrer headers

Logging / Monitoring / Error handling

อย่า log secret (รวมถึง request headers เช่น Authorization)

ทำ redaction ใน logger:

    • mask token เหลือท้าย 4 ตัว
    • remove fields เช่น password, api_key, secret

ระวัง error page / stack trace ใน production:

    • ปิด debug mode
    • จัดการ exception แล้วตอบ error แบบไม่เผยข้อมูลภายใน

การจัดการสิทธิ์และการหมุนคีย์ (Rotation)

มีนโยบาย rotation เช่น ทุก 60–90 วัน (แล้วแต่ความเสี่ยง)

รองรับ rollout แบบไม่ downtime:

    • backend ยอมรับทั้ง “คีย์เก่าและคีย์ใหม่” ช่วงหนึ่ง (dual keys)
    • แล้วค่อย revoke คีย์เก่า

เก็บประวัติการออกคีย์ / revoke / ผู้รับผิดชอบ

การทดสอบและ CI/CD

ใน CI ให้ใช้ secret store ของระบบ CI (เช่น GitHub Actions Secrets / GitLab CI Variables)

แยก secret สำหรับ test/staging โดยเฉพาะ

ใน unit test หลีกเลี่ยงการใช้ secret จริง:

    • mock external API
    • ใช้ dummy key ที่ไม่มีสิทธิ์

Checklist แบบสั้น

  • ไม่มี secret ใน repo (รวม history)
  • ใช้ env vars / secret manager แทน hardcode
  • React ไม่มี secret ใด ๆ ใน bundle
  • Flask ปิด debug ใน production
  • logger มีการ redaction (Authorization/password/api_key)
  • แยก secret ต่อ environment + least privilege
  • มีแผน rotation/revoke และทำได้จริง

ตัวอย่างโครงสร้างไฟล์ที่พบบ่อย

backend/

    • .env (ignored)
    • .env.example (commit ได้)
    • app/config.py (อ่านค่าจาก env)

frontend/

    • .env (มักไม่ใส่ secret; ถ้ามีให้เป็นแค่ public config)
    • .env.production (ระวัง: ยังถือว่า public หลัง build)
    • src/config.ts (อ่าน public config)

ถ้าคุณอยากได้ “ตัวอย่าง template” สำหรับ Flask config + วิธีเสิร์ฟ runtime config ให้ React (แบบไม่ bake ตอน build) บอกสแต็กที่ใช้ deploy (เช่น Docker/K8s/Render/Fly/EC2) เดี๋ยวผมเขียนให้เป็นแพตเทิร์นครบชุดได้เลย.