SSD Nodes Learn
指南 Matt Connor作者: Matt Connor · 已更新 2026-07-24

如何以非特權使用者執行服務以提升安全性

避免以 root 執行服務以防止漏洞導致系統被攻破。本文介紹如何透過建立專用系統帳號,或使用 systemd 的 DynamicUser 功能,實踐最小權限原則並強化服務隔離性。

為什麼不直接以 root 執行所有程式

Root 在機器上擁有最高權限:可以讀取所有檔案、更改任何設定、刪除整個系統。當你以 root 身份執行服務時,等於將所有權限都交給該服務。如果該服務存在可被利用的漏洞,攻擊者不僅能控制該服務,還能取得 root 權限,進而控制整台伺服器。使用非特權使用者執行可以限制損害範圍。若執行受限帳號的服務出現漏洞,攻擊者僅能接觸該帳號有權存取的資源,而這些資源通常極少。

這就是最小權限原則 (Principle of Least Privilege):賦予系統每個部分執行任務所需的精確權限,且不多給。這是限制入侵後影響範圍 (blast radius) 最有效的方法,且在現代伺服器上實施的成本幾乎為零。

為每個服務建立專用帳號

傳統做法是為每個服務建立獨立的系統使用者,該使用者僅擁有該服務的檔案所有權且無法登入。一個 Web App 的系統帳號可能如下所示:

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

每個 flag 都至關重要。--system 使其成為服務帳號而非人類登入帳號。--no-create-home 跳過不需要的家目錄。--shell /usr/sbin/nologin 意味著即使攻擊者取得該帳號,也無法使用它開啟 shell。該帳號僅用於擁有處理程序及其檔案。

接著僅賦予該使用者必要的檔案權限,不多給:

sudo chown -R appsvc:appsvc /opt/myapp

現在服務可以讀寫自己的目錄,且無法存取磁碟上的其他任何地方。如果服務被攻破,攻擊者可以修改的檔案僅限於 /opt/myapp;該帳號仍可讀取所有世界可讀 (world-readable) 的檔案,但無法修改系統的其他部分。

使用 systemd 以該使用者身份執行

建立帳號後,在 unit file 中指定 systemd 以該帳號執行服務:

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

User=appsvc 意味著處理程序是以該帳號的受限權限啟動,而非 root。這是透過 systemd 執行應用程式的標準做法,建議為每個撰寫的 unit 服務都這樣做。

或使用 DynamicUser 完全跳過帳號

systemd 可以進一步為你建立一個臨時使用者,該使用者僅在服務執行期間存在。設定 DynamicUser=yes 即可完全無需管理帳號:

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

啟動時,systemd 會分配一個未被使用的 user ID;停止時,則釋放該 ID。服務還會獲得一個私有的 /tmp(對大部分檔案系統的唯讀視圖),以及一個由 StateDirectory=/var/lib/myapp 下建立並交給它的可寫入 state directory。對於僅需要自身 state directory 的獨立服務,DynamicUser=yes 是獲得強效隔離最省力的方法,因為完全沒有長期的帳號供攻擊者瞄準。

手寫 unit file 非常繁瑣,而正確設定強化指令 (hardening directives) 才是關鍵。the systemd service and timer guide 中的 generator 可以幫你填入這些選項,確保 unit 一次就設定正確。

這與其他安全層的關係

最小權限只是其中一層,它與其他層級協同工作而非取代它們。default-deny firewall 控制哪些流量可以到達服務;以非特權使用者執行服務可控制服務被入侵後的行為;而 hardened SSH 則從源頭防止攻擊者進入機器。單靠任何一層都不夠,結合使用才能確保單一服務的漏洞不會演變成整台伺服器的淪陷。

在繼續之前,請執行整台機器的強化檢查清單,並生成一份個人化副本以供參考:

ToolVPS hardening checklist

FAQ

為什麼我不應該以 root 身份執行服務?

因為 root 在機器上擁有最高權限,若以 root 執行且被攻破的服務會將整台伺服器交給攻擊者,而不僅僅是該服務。請將 root 留給管理工作,並以受限使用者執行所有長期運行的服務。

如何建立一個無法登入的使用者?

執行 sudo useradd --system --no-create-home --shell /usr/sbin/nologin NAMEnologin shell 意味著即使憑證被盜,該帳號也無法開啟互動式工作階段,--system 將其標記為服務帳號,而 --no-create-home 則跳過不需要的家目錄。使用 chown 僅賦予其自身檔案的所有權。

什麼是 systemd DynamicUser?

DynamicUser=yes 告訴 systemd 為服務建立一個僅在執行期間存在的臨時使用者,因此你無需管理長期帳號。它還會為服務提供私有的 /tmp(大部分為唯讀的檔案系統視圖)和受管理的 state directory。這是以臨時、低權限身份執行獨立服務最省力的方法。

以非 root 使用者執行可以取代防火牆嗎?

不行。它們保護的是不同的東西。以非特權使用者執行是限制服務被入侵後的行為,而防火牆則是限制哪些流量可以接觸到該服務。請同時使用兩者以及強化後的 SSH,讓每一層都能補足其他層無法涵蓋的範圍。

服務使用者應該擁有哪些檔案?

僅限該服務實際需要的檔案,不多給。使用 sudo chown -R svc-app:svc-app /opt/svc-app 將應用程式目錄的所有權交給該帳號,並將數據交給它,其餘所有權保留給 root。一個好的模式是:應用程式目錄使用 sudo chown -R svc-app:svc-app /opt/svc-app,而位於 /etc 下的設定檔保持 root 所有權且僅供服務讀取。目標是如果處理程序被攻破,其可修改的檔案僅限於其自身的數據,而非系統的其他部分。

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