ความปลอดภัย
หน้านี้สอนอะไร
Easy CMS ป้องกันอะไรให้บ้าง อะไรยังเป็นหน้าที่ของคุณ และเช็กลิสต์ก่อนขึ้นระบบจริง
ควรอ่านก่อน: การควบคุมสิทธิ์ และ ผู้ใช้และการยืนยันตัวตน
สิ่งที่ Easy CMS ทำให้
บัญชีและ session
- รหัสผ่าน hash ด้วย scrypt (N=2¹⁷) และไม่มี API ไหนส่งคืน ต้องยาวอย่างน้อย 8 ตัวอักษร
- session token สุ่มขึ้นมา เซ็นด้วย
EASY_CMS_SECRETและเก็บเฉพาะค่า hash สำเนาของฐานข้อมูลจึงใช้ login ไม่ได้ - cookie เป็น
HttpOnly,SameSite=LaxและSecureบน production (หรือเมื่อใช้ HTTPS) - จำกัดการ login: ล้มเหลว 5 ครั้งต่อ email (และ IP ถ้ารู้) ภายใน 15 นาที การ login จะตอบ
429(auth.maxLoginAttempts,auth.lockWindow) - การ logout การเปลี่ยนรหัสผ่าน หรือการปิดใช้งานผู้ใช้ จะปิดทุก session ของคนนั้น
Request
- CSRF: การเขียนข้อมูลที่ยืนยันตัวตนด้วย session cookie ต้องส่ง CSRF token ของ session ใน header
x-csrf-tokenและOriginต้องเป็นของ API เองหรืออยู่ในauth.trustedOriginsrequest ข้ามเว็บที่ไม่มีOriginจะถูกปฏิเสธ ส่วน request ที่ใช้ Bearer token ไม่ต้องใช้ CSRF token (browser ไม่ส่ง Bearer token ไปเอง) - CORS ปิดเป็นค่าเริ่มต้น
corsระบุ origin ที่โค้ดใน browser เรียก API ได้ และมีเฉพาะauth.trustedOriginsที่ส่ง cookie ได้ origin ในcorsเขียนข้อมูลได้ด้วยถ้าไม่มี session cookie (เช่น ฟอร์มสาธารณะ) เพราะไม่มี session ให้ปลอม และกฎสิทธิ์ของ collection ยังเป็นตัวตัดสิน - ขนาด body จำกัดที่ 1 MB (JSON) และ
upload.maxFileSize(ไฟล์ ค่าเริ่มต้น 10 MB) - error แสดงรายละเอียดเฉพาะตอนพัฒนา บน production error ที่ไม่คาดคิดจะตอบ
Internal Server Errorและบันทึก log ไว้ที่ server
เนื้อหา
- สิทธิ์ปิดเป็นค่าเริ่มต้น: ถ้าไม่มีกฎ มีเฉพาะผู้ใช้ที่ login ที่อ่านหรือแก้ collection ได้ กฎระดับ field จะเอา field ออกจากผลลัพธ์และไม่รับค่าของ field นั้น
- ไฟล์อัปโหลด ถูกตรวจจากเนื้อไฟล์ (ไม่ใช่ชื่อไฟล์) จำกัดขนาด เปลี่ยนชื่อ และส่งพร้อม
Content-Security-Policy: sandboxและnosniffไฟล์ SVG หรือ HTML ที่อัปโหลดจึงรัน script บนเว็บคุณไม่ได้ - การแสดง rich text (
renderRichText) escape ข้อความและ attribute และตัด URL ที่ไม่ปลอดภัย เช่นjavascript: - ลิงก์ตัวอย่าง (preview) มี token ที่เซ็นแล้วสำหรับเอกสารหรือ global เดียว และหมดอายุใน 1 ชั่วโมง
หน้า admin
- หน้า admin ส่ง Content Security Policy แบบเข้มงวด (script มาจาก origin ของคุณเท่านั้น),
X-Frame-Options: DENYและReferrer-Policy: same-origin - Admin module ถูกส่งจาก server ของคุณให้เฉพาะผู้ใช้ที่ login และ config จะไม่รับ URL ของเว็บอื่น
สิ่งที่ยังเป็นหน้าที่ของคุณ
- เก็บ
EASY_CMS_SECRETเป็นความลับและให้ยาว (สุ่ม 32 ตัวอักษรขึ้นไป เช่นopenssl rand -hex 32) ถ้าเปลี่ยนค่านี้ ทุกคนจะถูก logout - เขียนกฎสิทธิ์อย่างตั้งใจ โดยเฉพาะ
readcollection จะเป็นสาธารณะเมื่อคุณกำหนดเท่านั้น เช่นread: () => trueหรือ "เฉพาะที่เผยแพร่แล้ว" - ให้บทบาทเท่าที่จำเป็น: ผู้แก้เนื้อหาใช้
editorไม่ใช่adminมีแต่ admin ที่จัดการผู้ใช้ได้ - ติดตั้งเฉพาะ plugin ที่เชื่อถือได้ plugin ทำงานบน server ของคุณ และ admin component ของมันทำงานด้วยสิทธิ์ของผู้ที่ login อยู่
- review migration ก่อน deploy และอัปเดต dependency สม่ำเสมอ
- สำรองข้อมูล ทั้งฐานข้อมูลและไฟล์อัปโหลด ดู Backup
เช็กลิสต์ก่อนขึ้นระบบจริง
- [ ] ตั้ง
EASY_CMS_SECRETใน environment ของ server แล้ว ไม่ใช่มีแค่ใน.envบนเครื่องคุณ - [ ]
NODE_ENV=productionและเว็บให้บริการผ่าน HTTPS - [ ] กฎ
readของทุก collection เป็นไปตามที่ตั้งใจ ลองทดสอบตอนไม่ได้ login - [ ]
corsและauth.trustedOriginsมีเฉพาะ origin ของคุณเอง - [ ] ถ้าอยู่หลัง proxy ที่คุณควบคุม ให้เปิด trust proxy (
trustProxyสำหรับ Nuxt และ Next.js,--trust-proxyสำหรับ standalone) เพื่อให้การจำกัด login เห็น IP จริงของผู้ใช้ - [ ] admin คนแรกใช้รหัสผ่านที่แข็งแรง และคนอื่นใช้บทบาท
editor - [ ] รัน migration แล้ว (
easy-cms migrate) และมีการสำรองข้อมูลตามรอบ
การแจ้งช่องโหว่
แจ้งช่องโหว่แบบส่วนตัวตามที่อธิบายใน SECURITY.md อย่าแจ้งใน issue สาธารณะ
ขั้นต่อไป
- การควบคุมสิทธิ์: กฎระดับ collection เอกสาร และ field
- Migration และการ deploy: ส่งการเปลี่ยน schema ขึ้นระบบอย่างปลอดภัย