问题:我有一个通过 cron 作业定期运行的脚本以 root 身份,但我想让人们也能通过网页异步启动它。(将编写脚本以确保它不会运行重叠实例等。)
我不需要用户登录或拥有账户,他们只需单击按钮,如果脚本已准备好运行,它就会运行。用户可以选择脚本的参数(经过严格筛选作为输入),但为了简单起见,我们假设他们只需选择要按的按钮即可。
作为一个简单的测试,我在 cgi-bin 中创建了一个 Python 脚本。将其 chown 为 root:root,然后对其应用“chmod ug+”并没有得到预期的结果:它仍然认为它拥有 Web 服务器帐户的有效组......据我所知,这是不允许的。
我读到用编译好的 cgi 程序包装它可以完成这项工作,所以我创建了一个 C 包装器来调用我的脚本(它的权限恢复正常)并赋予可执行文件 root 权限和 setuid 位。那有效......脚本的运行就像 root 运行它一样。
我的主要问题是,这是正常的吗(需要二进制包装器来完成工作)并且这是安全的方法吗?这不是面向世界的,但我仍然想学习最佳实践。
更广泛地说,我经常想知道为什么编译后的二进制文件实际上比脚本更“可信”?我认为你会信任一个人类可读的文件,而不是一个神秘的二进制文件。如果攻击者可以编辑一个文件,那么你已经有麻烦了,如果这是一个你无法轻易检查的文件,那就更麻烦了。简而言之,基于这一点,我预计情况会相反。你的想法?
答案1
首先:不要这样做,或者至少不允许任何参数从网络传递到以 root 身份运行的应用程序。
现在来回答您的实际问题:当您编写脚本(在本例中为 Python)时,它会由解释器执行。因此,为了能够以 root 身份运行脚本,您需要将 Python 解释器设置为 suid-root,但您实际上并不想这样做。这是因为您的脚本本身并不是可执行文件,而只是解释器的一组规则。当您使用二进制可执行文件包装脚本时,您现在又有一个获得 root 权限的可执行文件,并且从可执行文件调用的 Python 解释器也具有 root 权限。有关此内容的更多信息,请参阅无法在 Shell 脚本上设置 UID和http://www.diablotin.com/librairie/networking/puis/ch05_05.htm
也就是说,按照@SvenW 建议的那样通过 sudo 调用脚本应该可以正常工作。
答案2
另一个答案,因为这是一个完全不同(而且更通用)的方法。有人可能会说这是做这些事情的规范方法:)
将您的 Apache 用户(无论它如何命名,我假设www-data
)放入sudoers 文件(带有visudo
)中有一行非常具体的代码,允许他仅从yourscript.py
本地计算机(hostname
)运行,无需密码。如下所示:
www-data hostname=(root)NOPASSWD:/path/to/yourscript.py
然后,您的 CGI 脚本可以通过调用来启动该脚本sudo /path/to/yourscript.py
。
当然,您必须格外确保您可能用于此脚本的参数完全限制在允许的值内 - 最好是从 cgi 包装器脚本和yourscript.py
.
答案3
我认为最简单(而且相当安全)的方法是间接的:让网页在用户点击按钮时在某处创建一个文件,并修改脚本,使其仅在文件存在时运行,然后将其删除。然后每分钟从 cron 作业运行此脚本。您甚至可以使用此文件为脚本提供参数(当然这需要特别注意)。
这留下了改进的空间(多个用户同时点击就是一次),但我已多次使用此方法进行清理和一次性操作。