SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-30

systemd 服務如何以非特權使用者執行

以 root 執行服務,任何漏洞都可能導致整台伺服器遭入侵。了解如何建立專用 system user,或使用 systemd 的 DynamicUser 限制影響範圍。

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

root 可以對機器執行任何操作:讀取所有檔案、變更任何設定,或刪除整個系統。以 root 執行服務時,你會將這些權限全部交給該服務。若服務存在可遭攻擊者利用的錯誤,攻擊者取得的不只是服務,而是 root 權限;而 root 代表整台伺服器。以未具特權的使用者執行服務,可以限制損害範圍。以受限帳戶執行的服務若存在錯誤,攻擊者只能存取該帳戶有權限操作的內容,而這些內容應該幾乎沒有。

這就是最小權限原則:為系統的每個部分提供完成工作所需的確切存取權限,不提供其他權限。這是限制遭入侵後影響範圍最有效的單一做法。在現代伺服器上,採用這項原則幾乎不需要付出成本。

每項服務使用專用帳號

傳統做法是為每項服務建立個別的 system user。該帳號只擁有該服務的檔案,且無法登入。Web 應用程式使用的 system account 可以如下建立:

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

每個 flag 都有作用。--system 會將其設為服務帳號,而不是一般使用者的登入帳號。--no-create-home 會略過不需要的 home directory。--shell /usr/sbin/nologin 表示即使攻擊者以某種方式取得該帳號,也無法使用它開啟 shell。此帳號只用來擁有程序及其檔案。

接著只將服務所需的檔案授予該使用者,不要授予其他權限:

sudo chown -R appsvc:appsvc /opt/myapp

現在,該服務只能讀取及寫入自己的目錄,無法存取磁碟上的其他位置。如果服務遭到利用,攻擊者能修改的檔案僅限於 /opt/myapp;該帳號仍可讀取所有 world-readable 的檔案,但無法修改系統的其他部分。

讓 systemd 以該使用者身分執行

建立帳戶後,請設定 systemd 以該帳戶身分執行服務。在 unit 檔案中加入一行即可:

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

User=appsvc 表示程序會以該帳戶受限的權限啟動,而不是以 root 的權限啟動。這是讓應用程式在 systemd 下執行時標準且常用的方式。凡是為服務撰寫 unit 的情況,都值得採用。不過,如果 systemd 監控的是錯誤的程序,降低權限也無法解決問題。因此,如果 daemon 已靜默結束,但 unit 仍回報 active,請確認你是否已依程序的啟動方式選擇正確的 Type=

或完全略過帳號,改用 DynamicUser

systemd 還能更進一步,為您建立一次性使用者。該使用者只在服務執行期間存在。設定 DynamicUser=yes 後,您完全不需要管理帳號:

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

啟動時,systemd 會配置未使用的使用者 ID;停止時則釋放該 ID。服務也會取得私有的 /tmp、大部分檔案系統的唯讀檢視,以及位於 /var/lib/myapp 下的可寫入狀態目錄。StateDirectory= 會建立該目錄並交給服務使用。在 SysV init 中無法做到這些,因為降權處理由各服務自己的啟動指令碼決定,而各指令碼的實作可能不同。這項差距也是 各發行版最初改用 systemd 的原因之一。對於只需要自己的狀態目錄、且具備完整自足性的服務,DynamicUser=yes 是取得強隔離的最低成本方式,因為根本不存在可供攻擊者鎖定的長期帳號。

手動撰寫 unit 相當繁瑣,而正確設定強化指令才是其中最有價值的部分。systemd 服務與計時器指南中的產生器可以替您填入這些選項,讓 unit 第一次就正確。

這項設定如何與其他措施配合

最小權限是其中一層,應與其他措施搭配使用,而不是取代它們。預設拒絕的防火牆會控制哪些流量可以到達服務;以非特權使用者身分執行服務,則會限制服務遭到入侵後可以執行的操作;強化 SSH則能在攻擊者入侵主機前,先阻止其登入。這些措施沒有任何一項單獨就足夠;搭配使用時,即使某項服務存在錯誤,也不會導致整台伺服器遭到入侵。託管會保護機密資料的服務時,更能看出這些層的限制:受限制的帳戶能限制遭入侵程序可以存取的內容,但自行託管的密碼管理器,例如 Vaultwarden仍取決於您如何保護其管理權杖與備份檔案,而使用者隔離無法涵蓋這兩者。

繼續下一步前,請先依照整台主機的強化檢查清單逐項確認,並產生一份個人化副本作為操作依據:

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、大致為唯讀的檔案系統檢視,以及由 systemd 管理的狀態目錄。對於自包含服務而言,這是以可拋棄的低權限身分執行服務的最低成本方式。

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

不行。兩者防護的對象不同。以非特權使用者執行服務,可限制服務遭到入侵後能執行的操作;防火牆則限制哪些流量可以觸及服務。兩者應搭配強化過的 SSH 一起使用,讓每一層防護補足其他層無法涵蓋的部分。

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

只應擁有服務實際需要的檔案,不要多給任何權限。將工作目錄與資料的擁有權授予該帳號,其餘檔案則維持由 root 擁有。一種良好做法是讓應用程式目錄使用 sudo chown -R svc-app:svc-app /opt/svc-app,而 /etc 下的設定檔維持由 root 擁有,僅允許服務讀取。目標是程序即使遭到入侵,可修改的檔案也只限於自己的資料,不會擴及系統其餘部分。

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