SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-08-28

วิธีรัน Service ด้วยสิทธิ์ User ปกติบน Linux

การรัน Service ด้วยสิทธิ์ root เพิ่มความเสี่ยงหากเกิดช่องโหว่ เรียนรู้วิธีจำกัดสิทธิ์ด้วยการสร้างบัญชีเฉพาะหรือใช้ฟีเจอร์ DynamicUser ใน systemd เพื่อความปลอดภัยสูงสุดของเซิร์ฟเวอร์

เหตุใดจึงไม่ควรเรียกใช้งานทุกอย่างด้วยสิทธิ์ root

บัญชี root มีสิทธิ์กระทำการทุกอย่างบนเครื่อง ไม่ว่าจะเป็นการอ่านไฟล์ทุกไฟล์ การเปลี่ยนการตั้งค่าทุกอย่าง หรือการลบระบบทิ้งทั้งหมด เมื่อคุณเรียกใช้งานบริการด้วยสิทธิ์ root คุณกำลังมอบอำนาจทั้งหมดนั้นให้กับบริการดังกล่าว หากบริการนั้นมีช่องโหว่ที่ผู้โจมตีสามารถใช้ประโยชน์ได้ ผู้โจมตีจะไม่ได้รับเพียงแค่สิทธิ์ของบริการนั้นเท่านั้น แต่จะได้สิทธิ์ระดับ root ซึ่งหมายถึงการควบคุมเซิร์ฟเวอร์ทั้งหมด การเรียกใช้งานด้วยผู้ใช้ที่ไม่มีสิทธิ์พิเศษ (unprivileged user) จะช่วยจำกัดความเสียหายที่อาจเกิดขึ้น หากบริการที่ทำงานด้วยบัญชีที่มีสิทธิ์จำกัดมีช่องโหว่ ผู้โจมตีจะเข้าถึงได้เพียงสิ่งที่บัญชีนั้นเข้าถึงได้เท่านั้น ซึ่งโดยปกติแล้วควรจะเป็นสิ่งที่เข้าถึงได้น้อยที่สุด

นี่คือหลักการของสิทธิ์ขั้นต่ำ (principle of least privilege) คือการให้สิทธิ์แต่ละส่วนของระบบเท่าที่จำเป็นต่อการทำงานเท่านั้น และไม่ให้สิทธิ์เกินความจำเป็น นี่เป็นแนวทางปฏิบัติที่มีประสิทธิภาพที่สุดในการจำกัดขอบเขตความเสียหายหากระบบถูกบุกรุก และบนเซิร์ฟเวอร์สมัยใหม่ การนำหลักการนี้ไปใช้แทบไม่มีต้นทุนใดๆ เลย

การใช้บัญชีผู้ใช้เฉพาะสำหรับแต่ละบริการ

แนวทางมาตรฐานคือการสร้าง system user แยกต่างหากสำหรับแต่ละบริการ โดยให้บัญชีนั้นเป็นเจ้าของเฉพาะไฟล์ของบริการดังกล่าวและไม่สามารถล็อกอินเข้าสู่ระบบได้ บัญชีระบบสำหรับเว็บแอปพลิเคชันอาจมีลักษณะดังนี้:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin appsvc

ทุก flag มีความสำคัญ --system กำหนดให้เป็นบัญชีสำหรับบริการ ไม่ใช่บัญชีสำหรับผู้ใช้งานทั่วไป --no-create-home ข้ามการสร้าง home directory ซึ่งไม่จำเป็นต้องใช้ --shell /usr/sbin/nologin หมายความว่าแม้ผู้โจมตีจะเข้าถึงบัญชีนี้ได้ ก็ไม่สามารถเปิด shell เพื่อใช้งานได้ บัญชีนี้มีไว้เพื่อเป็นเจ้าของ process และไฟล์ที่เกี่ยวข้องเท่านั้น

จากนั้นกำหนดสิทธิ์ให้ผู้ใช้รายนั้นเข้าถึงเฉพาะไฟล์ที่จำเป็นเท่านั้น:

sudo chown -R appsvc:appsvc /opt/myapp

ขณะนี้บริการดังกล่าวสามารถอ่านและเขียนได้เฉพาะในไดเรกทอรีของตนเองเท่านั้น และไม่มีสิทธิ์เข้าถึงส่วนอื่นของดิสก์ หากบริการถูกโจมตี ไฟล์ที่ผู้โจมตีสามารถแก้ไขได้จะถูกจำกัดอยู่เพียงแค่ใน /opt/myapp เท่านั้น บัญชีนี้ยังคงสามารถอ่านไฟล์ที่อนุญาตให้ทุกคนอ่านได้ แต่ไม่สามารถแก้ไขส่วนอื่นของระบบได้

กำหนดให้ systemd รันด้วยผู้ใช้นั้น

เมื่อมีบัญชีผู้ใช้แล้ว ให้กำหนดให้ systemd รัน service ด้วยบัญชีดังกล่าว ในไฟล์ unit ให้เพิ่มบรรทัดนี้:

[Service]
ExecStart=/opt/myapp/bin/server
User=appsvc
Group=appsvc

User=appsvc หมายความว่ากระบวนการจะเริ่มต้นด้วยสิทธิ์ที่จำกัดของบัญชีนั้นแทนที่จะเป็นสิทธิ์ของ root นี่เป็นวิธีมาตรฐานที่ใช้กันทั่วไปในการรันแอปพลิเคชันภายใต้ systemd และควรทำสำหรับทุก service ที่คุณเขียน unit ไฟล์ให้ การลดสิทธิ์จะไม่ช่วยหาก systemd กำลังตรวจสอบกระบวนการที่ผิด ดังนั้นหาก unit ยังคงรายงานสถานะเป็น active หลังจากที่ daemon ปิดตัวลงอย่างเงียบๆ ให้ตรวจสอบว่าคุณได้ เลือก Type= ที่ถูกต้องสำหรับวิธีการเริ่มต้นกระบวนการของคุณ แล้วหรือไม่

หรือข้ามการสร้างบัญชีผู้ใช้ไปเลยด้วย DynamicUser

systemd สามารถทำได้มากกว่านั้นโดยการสร้างผู้ใช้ชั่วคราวให้คุณ ซึ่งจะมีตัวตนอยู่เฉพาะในขณะที่บริการทำงานเท่านั้น เพียงตั้งค่า DynamicUser=yes คุณก็ไม่จำเป็นต้องจัดการบัญชีผู้ใช้ใดๆ เลย:

[Service]
ExecStart=/opt/myapp/bin/server
DynamicUser=yes
StateDirectory=myapp

เมื่อเริ่มทำงาน systemd จะจัดสรร ID ผู้ใช้ที่ไม่ได้ใช้งานให้ และจะปล่อยคืนเมื่อหยุดทำงาน บริการจะได้รับ /tmp ส่วนตัว, มุมมองระบบไฟล์แบบอ่านอย่างเดียวเกือบทั้งหมด และไดเรกทอรีสถานะที่เขียนได้ภายใต้ /var/lib/myapp ซึ่ง StateDirectory= จะเป็นผู้ตั้งค่าและส่งมอบให้ สิ่งเหล่านี้ไม่สามารถทำได้ใน SysV init ซึ่งการลดสิทธิ์ผู้ใช้ขึ้นอยู่กับสิ่งที่สคริปต์เริ่มต้นของแต่ละบริการทำเอง ช่องว่างดังกล่าวเป็นเหตุผลสำคัญส่วนหนึ่งของ สาเหตุที่ดิสทริบิวชันต่างๆ เปลี่ยนมาใช้ systemd ตั้งแต่แรก สำหรับบริการที่ทำงานด้วยตัวเองและต้องการเพียงไดเรกทอรีสถานะของตนเอง DynamicUser=yes เป็นวิธีที่ใช้ความพยายามน้อยที่สุดในการสร้างการแยกส่วนที่แข็งแกร่ง เพราะไม่มีบัญชีผู้ใช้ที่คงอยู่ถาวรให้ผู้โจมตีมุ่งเป้าได้เลย

การเขียน unit ด้วยตนเองนั้นทำได้ยาก และการตั้งค่าคำสั่ง hardening ให้ถูกต้องคือหัวใจสำคัญของความปลอดภัย เครื่องมือสร้างใน คู่มือ systemd service และ timer สามารถเติมตัวเลือกเหล่านี้ให้คุณได้ เพื่อให้ unit ของคุณถูกต้องตั้งแต่ครั้งแรกที่สร้าง

แนวทางนี้สอดคล้องกับส่วนอื่นอย่างไร

หลักการ Least privilege เป็นเพียงชั้นหนึ่งเท่านั้น และมันทำงานร่วมกับชั้นอื่นแทนที่จะมาทดแทนกัน ไฟร์วอลล์แบบ default-deny จะควบคุมสิ่งที่สามารถเข้าถึงบริการได้ การรันบริการด้วยผู้ใช้ที่ไม่มีสิทธิ์พิเศษจะควบคุมสิ่งที่บริการนั้นทำได้หากถูกเจาะระบบ และ การตั้งค่า SSH ให้ปลอดภัย จะช่วยป้องกันผู้โจมตีไม่ให้เข้าถึงเครื่องได้ตั้งแต่แรก มาตรการเหล่านี้เพียงอย่างเดียวไม่เพียงพอ แต่เมื่อรวมกันแล้วจะช่วยให้บั๊กในบริการหนึ่งไม่กลายเป็นการถูกเจาะทั้งเซิร์ฟเวอร์ การโฮสต์สิ่งที่เก็บข้อมูลลับจะแสดงให้เห็นว่ามาตรการเหล่านี้มีขีดจำกัดอย่างไร บัญชีที่ถูกจำกัดสิทธิ์จะจำกัดสิ่งที่กระบวนการที่ถูกเจาะจะเข้าถึงได้ แต่ ตัวจัดการรหัสผ่านแบบ self-hosted อย่าง Vaultwarden ยังคงขึ้นอยู่กับวิธีการที่คุณปกป้อง admin token และไฟล์สำรองข้อมูล ซึ่งการแยกสิทธิ์ผู้ใช้ไม่ครอบคลุมถึงส่วนนี้

ก่อนที่คุณจะดำเนินการต่อ ให้ตรวจสอบรายการ hardening สำหรับทั้งเครื่องและสร้างสำเนาส่วนตัวเพื่อใช้เป็นแนวทางปฏิบัติ:

ToolVPS hardening checklist

FAQ

ทำไมฉันจึงไม่ควรเรียกใช้บริการในฐานะ root?

เนื่องจาก root มีสิทธิ์กระทำการทุกอย่างบนเครื่อง หากบริการที่รันด้วยสิทธิ์ root ถูกโจมตี ผู้โจมตีจะได้สิทธิ์ควบคุมเซิร์ฟเวอร์ทั้งหมด ไม่ใช่แค่ตัวบริการนั้น การรันบริการด้วยบัญชีผู้ใช้ที่มีสิทธิ์จำกัดจะช่วยจำกัดความเสียหายให้อยู่เฉพาะสิ่งที่บัญชีนั้นเข้าถึงได้เท่านั้น ควรสงวนสิทธิ์ root ไว้สำหรับการดูแลระบบ และรันบริการที่ทำงานต่อเนื่องทุกอย่างด้วยผู้ใช้ที่มีสิทธิ์จำกัด

ฉันจะสร้างผู้ใช้ที่ไม่สามารถล็อกอินได้อย่างไร?

ให้รัน sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAME โดยที่ shell แบบ nologin หมายความว่าบัญชีนี้จะไม่สามารถเปิดเซสชันแบบโต้ตอบได้แม้ข้อมูลประจำตัวจะถูกขโมยไป --system เป็นการระบุว่าเป็นบัญชีสำหรับบริการ และ --no-create-home จะข้ามการสร้าง home directory ที่ไม่จำเป็นออกไป ทั้งนี้ควรให้สิทธิ์ความเป็นเจ้าของเฉพาะไฟล์ของบัญชีนั้นด้วย chown

DynamicUser ของ systemd คืออะไร?

DynamicUser=yes เป็นการสั่งให้ systemd สร้างผู้ใช้ชั่วคราวสำหรับบริการนั้นๆ ซึ่งจะมีตัวตนอยู่เฉพาะในขณะที่บริการทำงานอยู่เท่านั้น คุณจึงไม่ต้องจัดการกับบัญชีที่มีอายุการใช้งานยาวนาน นอกจากนี้ยังช่วยให้บริการมี /tmp ส่วนตัว, มุมมองระบบไฟล์ที่เกือบจะเป็นแบบอ่านอย่างเดียว และไดเรกทอรีสถานะที่มีการจัดการให้ นี่เป็นวิธีที่ใช้ความพยายามน้อยที่สุดในการรันบริการแบบเบ็ดเสร็จภายใต้ตัวตนที่ใช้แล้วทิ้งและมีสิทธิ์ต่ำ

การรันด้วยผู้ใช้ที่ไม่ใช่ root สามารถทดแทน firewall ได้หรือไม่?

ไม่ได้ ทั้งสองอย่างทำหน้าที่ปกป้องคนละส่วนกัน การรันด้วยผู้ใช้ที่ไม่มีสิทธิ์จะจำกัดสิ่งที่บริการทำได้หากถูกเจาะระบบ ในขณะที่ firewall จะจำกัดสิ่งที่สามารถเข้าถึงบริการได้ตั้งแต่ต้น ควรใช้ทั้งสองอย่างร่วมกันพร้อมกับการตั้งค่า SSH ที่รัดกุม เพื่อให้แต่ละชั้นปกป้องในส่วนที่ชั้นอื่นทำไม่ได้

ไฟล์ใดบ้างที่ผู้ใช้ของบริการควรเป็นเจ้าของ?

เฉพาะไฟล์ที่บริการจำเป็นต้องใช้จริงๆ เท่านั้น ให้บัญชีนั้นเป็นเจ้าของไดเรกทอรีทำงานและข้อมูลของตัวเอง ส่วนไฟล์อื่นๆ ทั้งหมดควรให้ root เป็นเจ้าของ รูปแบบที่ดีคือการใช้ sudo chown -R svc-app:svc-app /opt/svc-app สำหรับไดเรกทอรีแอปพลิเคชัน ในขณะที่การตั้งค่าภายใต้ /etc ควรให้ root เป็นเจ้าของและอนุญาตให้เฉพาะบริการอ่านได้เท่านั้น เป้าหมายคือหากกระบวนการทำงานถูกบุกรุก ไฟล์ที่สามารถเปลี่ยนแปลงได้จะถูกจำกัดอยู่เพียงข้อมูลของตัวมันเอง ไม่ใช่ส่วนอื่นๆ ของระบบ

#security#least-privilege#systemd#users#hardening#linux