// docs / baas security / clerk hardening
Clerk security checklist: 20 ข้อ
Clerk จัดการ auth, session และ organization สำหรับแอปของคุณ — ซึ่งหมายความว่าการ integrate Clerk ที่ตั้งค่าผิดคือการ bypass auth, vector session-fixation หรือเส้นทางการรั่วไหล org checklist นี้คือ audit 20 ข้อข้าม key, การตั้งค่า session, webhook, organization, JWT template และการ monitor ต่อเนื่อง เครื่องมือ AI Coding เชื่อมต่อ Clerk อย่างรวดเร็วด้วยค่าเริ่มต้นที่สมเหตุสมผล; รายการนี้จับรายการที่พวกมันทิ้งไว้
สำหรับเบื้องหลังว่าทำไมการตั้งค่าผิดชั้น auth จึงเป็นจุดอ่อนของ AI tool โปรดดู ทำไมเครื่องมือ AI Coding ทิ้งช่องโหว่ด้านความปลอดภัย สำหรับ checklist คู่ขนานบน Auth0 โปรดดู Auth0 security checklist
Environment key และ allowlist ของ origin
Clerk ออก key สองตัวที่แตกต่างกันต่อโปรเจกต์ การผสมหรือการรั่วไหลของพวกมันเป็นโหมดความล้มเหลวแรก
- ใช้ publishable key (
pk_live_*ใน production,pk_test_*ใน dev) ในเบราว์เซอร์; ใช้ secret key (sk_live_*/sk_test_*) บนเซิร์ฟเวอร์เท่านั้น publishable key ปลอดภัยในNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY; secret key ต้องไม่มี prefix env สาธารณะและต้องไม่ปรากฏใน client component - ตรวจสอบว่าแอป production ใช้
pk_live_*ไม่ใช่pk_test_*Instance ทดสอบอนุญาตอีเมลที่ไม่ได้ยืนยันและปิด MFA — การปล่อย test mode ไป production เป็นการ bypass auth - ตั้งค่า origin ที่อนุญาตใน Clerk Dashboard Settings → Domains → Allowed origins ต้องระบุโดเมน production ของคุณอย่างแน่นอน รายการ origin ที่ว่างหรือใช้ wildcard ให้ผู้โจมตีสร้าง Clerk frontend ปลอมที่คุยกับ backend ของคุณได้
- หมุน secret key เมื่อมีการลาออกหรือสงสัยว่ารั่วไหล Dashboard → API Keys → Reset key เก่าถูก invalidate; redeploy โค้ดฝั่งเซิร์ฟเวอร์ด้วยค่าใหม่ก่อนหมุน
การตั้งค่า session
การหมดอายุของ session และ idle timeout คือความแตกต่างระหว่าง session ที่ถูกขโมยเป็นเหตุการณ์ 10 นาทีและเหตุการณ์ 30 วัน
- ตั้งค่า session inactivity timeout เป็น 30 นาทีหรือน้อยกว่าสำหรับแอป SaaS ที่จัดการข้อมูลละเอียดอ่อน Dashboard → Sessions → Inactivity timeout แอประดับธนาคารควรใช้ 5-10 นาที; SaaS มาตรฐาน 30-60 นาที; แอปผู้บริโภค 1-7 วัน ค่าเริ่มต้นคือ 7 วัน
- เปิดใช้การ revoke session เมื่อเปลี่ยน password, เปลี่ยนอีเมล และการลงทะเบียน MFA Dashboard → Sessions → Revoke on นี่คือเหตุการณ์ความปลอดภัยที่ผู้ใช้ริเริ่ม; session ที่มีอยู่บนอุปกรณ์อื่นควรถูกฆ่า
- ตรวจสอบ session ฝั่งเซิร์ฟเวอร์ในทุก protected route ไม่ใช่แค่ตอนเข้าสู่ระบบ ใน Next.js:
const { userId } = await auth();ใน server component / API route อ่าน JWT จาก cookie และ validate มัน ไม่เคยเชื่อใจการตรวจสอบเฉพาะ cookie - ตั้งค่า
SameSite=Lax(ค่าเริ่มต้น) หรือStrictบน session cookie ตรวจสอบใน DevTools → Application → CookiesSameSite=Noneเป็น vector CSRF — ห้ามใช้เว้นแต่คุณได้กำหนดการตั้งค่า auth ข้ามโดเมนอย่างชัดเจน
การตรวจสอบ webhook
Clerk webhook ยิงในเหตุการณ์ lifecycle ของผู้ใช้ (created, updated, deleted, session.ended) เป็นกลไกการ sync สำหรับฐานข้อมูลของคุณ — และ webhook ปลอมเป็น primitive การเขียนฐานข้อมูล
- ตรวจสอบ signature Svix บนทุก webhook Clerk webhook ถูกเซ็นโดย Svix ใช้
new Webhook(secret).verify(body, headers)ปฏิเสธด้วย401หากการตรวจสอบล้มเหลว - เก็บ webhook secret ใน environment variable ไม่ใช่ในโค้ด secret หมุนในการ regenerate Dashboard แต่ละครั้ง — deploy ของคุณต้องอ่านจาก env ไม่ใช่จากค่าคงที่
- Idempotency ในทุก handler การส่ง webhook สามารถซ้ำได้ ใช้ header
svix-idเป็น primary key ในตารางwebhook_eventsเพื่อ dedupe ห่อ state change และการ insert idempotency ใน transaction เดียวกัน - เมื่อ
user.deletedลบหรือทำให้ PII anonymous ภายใน 24 ชั่วโมง GDPR / CCPA ต้องการสิ่งนี้ Audit เส้นทางการลบ: ตารางใดถือข้อมูลของผู้ใช้นี้? ใช้ FK ON DELETE CASCADE ที่ที่ทำได้
Organization และสิทธิ์
หากคุณใช้ Clerk Organization ขอบเขต org คือการแยก tenant ทุก query ฝั่งเซิร์ฟเวอร์ต้องกรองด้วยมัน
- ในทุก API route อ่านทั้ง
userIdและorgIdจากauth()และกรอง query ฐานข้อมูลด้วยทั้งสองWHERE org_id = $orgId AND user_id = $userIdไม่เคยเชื่อใจorg_idจาก request body - <strong>Use Clerk role checks for privileged operations, not boolean checks against the user object.</strong> <code>has({ role: 'org:admin' })</code> reads the role from the verified JWT. A user can spoof a boolean on a stale client object; they cannot spoof a JWT claim.
- ทดสอบการแยก org ข้ามกับบัญชี org จริงสอง สร้าง Org A, เพิ่มข้อมูล, เข้าสู่ระบบ Org B ในเบราว์เซอร์อื่น พยายามอ่านข้อมูลของ Org A ผ่าน API response ต้องเป็น
403หรือ404
JWT template และการ integrate ภายนอก
JWT template ผลัก identity ของ Clerk ไปยัง Supabase, Firebase และ service downstream อื่น ๆ template ที่ตั้งค่าผิดเปิดเผย claim มากเกินไปหรือเปิดเผยข้อมูลที่คุณไม่ได้ตั้งใจ
- สำหรับ JWT template แต่ละตัว list claim ทุกตัวและยืนยันว่าจำเป็น Dashboard → JWT Templates template ที่ส่ง
emailและphoneไปยัง Supabase เปิดเผย PII ให้กับใครก็ตามที่อ่าน JWT ในเบราว์เซอร์ - ตั้งค่าหมดอายุสั้นบน JWT template ที่ใช้สำหรับการเรียก downstream ฝั่ง client 60 วินาทีสำหรับ API request downstream เป็นมาตรฐาน JWT ที่อายุยืนถูกขโมยและ replay
- ตรวจสอบ audience (
aud) claim ฝั่งผู้รับ Supabase, Firebase ฯลฯ ควรตรวจสอบว่าaudตรงกับ service identifier ที่คาดหวัง หากไม่มีสิ่งนี้ JWT ที่ออกสำหรับ service A สามารถ authenticate กับ service B
การ monitor operational
Auth คือแหล่ง log สัญญาณสูงสุดที่คุณมี ดูมัน
- แจ้งเตือนเมื่อมีการเข้าสู่ระบบล้มเหลวเพิ่มขึ้นต่อ IP / ต่อบัญชี อัตราความล้มเหลว 50 เท่าปกติเป็นการโจมตี credential stuffing Clerk ปล่อยเหตุการณ์เหล่านี้ไปยัง webhook; route ไปยัง SIEM ของคุณ
- รีวิวการเลื่อนไหลของการตั้งค่า session และ instance รายไตรมาส ค่าเริ่มต้นเปลี่ยนแปลงเมื่อ Clerk อัปเดต; "การตั้งค่าเก่า" กลายเป็นผิดอย่างเงียบ ๆ เมื่อเวลาผ่านไป Diff JSON export ของ Dashboard กับสำเนา last-known-good ล่าสุด
ขั้นตอนถัดไป
รัน FixVibe scan กับ URL production ของคุณ — check baas.clerk-auth0 แจ้ง publishable key ของ Clerk, test key ใน production และ secret key ที่ bundled สำหรับ checklist ที่เทียบเท่าบน Auth0 โปรดดู Auth0 security checklist สำหรับมุมมองภาพรวมข้าม BaaS provider อ่าน BaaS misconfiguration scanner
