如何允許非特權 apache/PHP 執行 root 任務(CentOS)
我正在 CentOS 6.3 機器上為我們的客戶設置一種個人保管箱。該伺服器可通過 SFTP 和基於 PHP 的專有 http 服務訪問。這台機器將在我們的 DMZ 中,因此它必須是安全的。因此,我讓 apache 以非特權使用者身份執行,加強了 apache、作業系統、PHP 的安全性,在 iptables 中應用了大量過濾並應用了一些限制性 TCP Wrapper。現在你可能已經懷疑這個即將到來了,SELinux 也被設置為強制執行。
我正在設置 PAM 以使用 MySQL,以便我在 Web 應用程序中的使用者可以登錄。這些使用者都將在一個只能將 SSH 用於 SFTP 的組中,並且使用者將被 chroot 到他們自己的“主”文件夾。
為了允許這個,SELinux 希望文件夾有 user_home_t 標籤。父目錄也只能由 root 寫入。如果不滿足這些限制,SELinux 將立即終止 SSH 管道。
需要通過 http 和 SFTP 訪問的文件,所以我製作了一個 SELinux 模組,以允許 Apache 搜尋/attr/讀/寫等到帶有 user_home_dir_t 標籤的目錄。
由於 sftp 使用者儲存在 MySQL 中,我想在創建使用者時設置他們的主目錄。這是一個問題,因為 Apache 沒有對 /home 目錄的寫入權限,它只能由 root 寫入,因為它需要讓 SELinux 和 OpenSSH 滿意。
基本上,我只需要讓 Apache 以 root 身份並且僅在 /home 內執行一些任務。所以我需要以某種方式暫時提升權限,或者讓 root 為 apache 執行這些任務。
我需要讓 apache 使用 root 權限執行以下操作。
mkdir /home/userdir/ mkdir /home/userdir/userdir chmod -R 0755 /home/userdir umask 011 /home/userdir/userdir chcon -R -t user_home_t /home/userdir chown -R user:sftp_admin /home/userdir/userdir chmod 2770 /home/userdir/userdir
這將為使用者創建一個家,現在我有一個可行的想法,cron。這意味著伺服器需要每分鐘檢查一次沒有家的使用者,然後在創建使用者時,界面將平均凍結 30 秒,然後才能確認帳戶創建,這是我不喜歡的。有人知道sudoers可以做些什麼嗎?或者任何其他想法都是受歡迎的……
謝謝你的時間!
創建一個實現您描述的命令的腳本,並在其上執行
setuid
以使其能夠在任何人呼叫它時以 root 身份執行。有關 setuid 的更多資訊,請參閱http://en.wikipedia.org/wiki/Setuid。在 PHP 中,您可以
system('/bin/setupNewUser');
像往常一樣呼叫,腳本將以 root 身份執行。限制注入機會並在禁用腳本上執行 setuid 的系統上工作的替代解決方案:
創建一個有 setuid 的小程序。下面列出了一個範例:
#include <stdlib.h> #include <iostream> #include <string> using namespace std; int main(int argc, char* argv[]) { if (argc != 2) { cout << "Invalid arguments"; return 1; } //make sure the argument passed to the script has only [a-z] for (char* i = argv[1]; *i != '\0'; i++) { //check if the current character falls outside an allowed range if (!( //Allowed ranges: // between a and z ('a' <= *i && *i <= 'z') // between 0 and 9 || ('0' <= *i && *i <= '9') // '_' or '-' || ('_' == *i) || ('-' == *i) )) { cout << "Illegal character in username: " << *i << endl; return 2; } } //append the username string command = string("/test/setupUser.sh "); command += string(argv[1]); //execute the command and return the result transparently // return system(command.c_str()); // * OR * // call mkdir directly }
從 php 呼叫 setuid 程序
system('/test/setupUser '.escapeshellarg($username));