ผลต่างระหว่างรุ่นของ "01204223/secrets"

จาก Theory Wiki
ไปยังการนำทาง ไปยังการค้นหา
แถว 1: แถว 1:
 
เราจะฝึกจัดการกับข้อมูลที่เป็นความลับในการพัฒนาเว็บแอพ
 
เราจะฝึกจัดการกับข้อมูลที่เป็นความลับในการพัฒนาเว็บแอพ
 +
 +
ก่อนอื่นอ่านภาพรวมในการจัดการก่อน
  
 
== แนวปฏิบัติทั่วไปในการจัดการ ''secrets'' (รหัสผ่าน / API keys) สำหรับเว็บแอป Flask + React ==
 
== แนวปฏิบัติทั่วไปในการจัดการ ''secrets'' (รหัสผ่าน / API keys) สำหรับเว็บแอป Flask + React ==
แถว 186: แถว 188:
  
 
ถ้าคุณอยากได้ “ตัวอย่าง template” สำหรับ Flask config + วิธีเสิร์ฟ runtime config ให้ React (แบบไม่ bake ตอน build) บอกสแต็กที่ใช้ deploy (เช่น Docker/K8s/Render/Fly/EC2) เดี๋ยวผมเขียนให้เป็นแพตเทิร์นครบชุดได้เลย.
 
ถ้าคุณอยากได้ “ตัวอย่าง template” สำหรับ Flask config + วิธีเสิร์ฟ runtime config ให้ React (แบบไม่ bake ตอน build) บอกสแต็กที่ใช้ deploy (เช่น Docker/K8s/Render/Fly/EC2) เดี๋ยวผมเขียนให้เป็นแพตเทิร์นครบชุดได้เลย.
 +
 +
== ทดลองกับบัญชีผู้ใช้ฐานข้อมูล mysql ==
 +
 +
เราได้ส่งบัญชีและรหัสผ่านผู้ใช้ mysql บนเครื่อง p1.secondtrain.org แล้ว  เราจะเริ่มโดยย้ายฐานข้อมูลของ Todo app ของเราไปใช้ mysql บนเซิร์ฟเวอร์  จากนั้นเราจะจัดการกับความลับนี้
 +
 +
=== เปลี่ยนฐานข้อมูล ===
 +
 +
=== จัดการกับรหัสผ่าน ===

รุ่นแก้ไขเมื่อ 16:07, 26 กุมภาพันธ์ 2569

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

ก่อนอื่นอ่านภาพรวมในการจัดการก่อน

เนื้อหา

แนวปฏิบัติทั่วไปในการจัดการ 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) เดี๋ยวผมเขียนให้เป็นแพตเทิร์นครบชุดได้เลย.

ทดลองกับบัญชีผู้ใช้ฐานข้อมูล mysql

เราได้ส่งบัญชีและรหัสผ่านผู้ใช้ mysql บนเครื่อง p1.secondtrain.org แล้ว เราจะเริ่มโดยย้ายฐานข้อมูลของ Todo app ของเราไปใช้ mysql บนเซิร์ฟเวอร์ จากนั้นเราจะจัดการกับความลับนี้

เปลี่ยนฐานข้อมูล

จัดการกับรหัสผ่าน