请不要这样做!

请不要这样做!

我正在 CentOS 6.3 机器上为我们的客户设置一种个人 Dropbox。该服务器将通过 SFTP 和基于 PHP 的专有 http 服务访问。这台机器将位于我们的 DMZ 中,因此必须是安全的。因此,我以非特权用户身份运行 apache,加强了 apache、OS、PHP 的安全性,在 iptables 中应用了大量过滤,并应用了一些限制性的 TCP Wrappers。现在您可能已经猜到这个即将到来,SELinux 也设置为强制执行。

我正在设置 PAM 以使用 MySQL,以便我的 Web 应用程序中的用户可以登录。这些用户将全部属于一个只能使用 SSH 进行 SFTP 的组,并且用户将被 chroot 到他们自己的“主”文件夹。

为了实现这一点,SELinux 要求文件夹具有 user_home_t 标记。此外,父目录必须仅由 root 可写。如果不满足这些限制,SELinux 将立即终止 SSH 管道。

这些文件需要通过 http 和 SFTP 访问,因此我制作了一个 SELinux 模块,以允许 Apache 搜索/属性/读取/写入等带有 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 做些什么吗?或者欢迎任何其他想法...

谢谢你的时间!

答案1

创建一个脚本来实现您描述的命令,并运行setuid它,以便在任何人调用它时以 root 身份运行。请参阅http://en.wikipedia.org/wiki/Setuid有关 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));

答案2

请不要这样做!

至少不是你建议的那样——Apache 没有理由这样做任何事物以 root 身份
运行。Apache 将拒绝以 root 身份运行(绑定到端口 80 的母进程除外),这一事实应该可以明显看出您所建议的恶劣程度。

另外,以 root 身份使用不受信任的用户输入进行任何操作都是一个糟糕的想法,而且肯定会发现黑客可以在输入框中输入所有有趣的东西,让你的系统做一些你意想不到的事情。


如果你确实想这样做:

  • 手动创建用户目录。
    这个手动步骤加上人工验证将拯救您的系统。允许任何不受信任的用户在 root shell 范围内输入只会自找麻烦。
    • 目录所有者应该是用户。
    • 目录组应该是 Apache 运行的组。
    • 目录权限可能应该是4770rwsrwx---

这将允许您的用户读取/写入/等目录的内容,并且目录上的 SetUID 位将强制用户成为所有文件的所有者(以便他们可以在使用 SCP/SFTP 登录时操作它们)。

相关内容