好吧,首先,我知道这个问题已经被问过几次了,但给出的答案并不完全令我满意。情况是这样的:我写了很多脚本来自动化各种维护任务,目的是完全自动化,一旦启动就不需要交互。现在,各种任务通常需要 root 权限(例如安装东西等),但更多时候我不喜欢使用超级用户权限执行命令或整个块(例如 wget,或提取从网络获取的存档等),以限制最坏情况下的损害。显然,为了满足我的目标,必须使用sudo
or调用脚本su
,并根据命令删除权限并重新获得权限。
现在我已经考虑了一些选择,但它们并不完全令我满意,因此我想在这里咨询专家,以了解哪一个是最好的解决方案(目的是使代码也易于其他人理解且逻辑结构合理)一旦发布):
1.) 将要以非 root 用户身份执行的位分解到外部文件中,并使用 . 从主脚本中执行该文件su <user> -c /path/to/file
。然而,这种方法有一些缺点:首先,它破坏了脚本的逻辑结构,使事情更难以理解和阅读,并且在定义和使用变量时产生问题。
2.) 定义别名或函数来缩短su <user> -c "command"
。这是一个非常糟糕的主意,因为 80% 的脚本都具有该特权前缀。除此之外,多行命令也是有问题的(比如包含我不想以 root 身份运行的命令的 if 结构)。
3.) 类似的东西su <user> << EOF << ... EOF
可以正确处理整个代码块。如果没有一个让我烦恼的问题:语法高亮,这将是最优雅的解决方案(因为脚本的逻辑结构没有被破坏)。我尝试过的所有主要编辑器都对此处文档内的整个块使用一种颜色。通读 80% 没有语法突出显示的脚本并不好。
没有真正优雅的方法来处理这个问题吗?类似su <user> -c ( ...)
不带引号的东西会很酷。或者我应该切换到另一个外壳? (现在我使用bash,我听说zsh有一个功能,允许设置EUID变量或类似的东西?)如果没有优雅的解决方案,哪种方法更好?
答案1
与zsh
,如果运行为root
并且您设置
EUID=1000
它将把 euid 设置为 1000。真正的 uid 仍将设置为 0,因此您可以返回到 EUID 0。您运行的任何程序也可以通过执行 a 来重新获得权限,setuid()
但如果目的是防止无意中损害而不是防范恶意软件,那么这就足够了。
#! /bin/zsh -
GID=1000 # optional
EUID=1000 # drop *effective* privileges
some-potentially-harmful-command-that-doesnt-need-superuser
and-another
EUID=0 some-command-that-needs-superuser
more-non-privileged-commands
EUID=0 UID=1000 # now drop privileges with no coming back
# alternatively:
# USERNAME=stephane # sets uid, gid, supplementary groups... based on the user db
请注意,您可以在命令持续时间内设置 EUID/UID...
UID=1000 the-command
但不是UID
或USERNAME
如果the-command
是内置的或函数,则zsh
不会派生不同的进程,因此无法恢复真实的用户 ID。
您还可以在子 shell 中设置EUID
// :UID
USERNAME
(EUID=0 USERNAME=stephane; untrusted-application)
(我们将 EUID 设置为 0,以便之后能够切换用户)。
答案2
一种解决方案是元编程:将各种非特权代码片段创建为单独的文件,并使用预处理器创建最终文件。这样,程序可以轻松地作为单独的位或作为整体来读取。进程之间的通信必须使用文件来完成,这有点麻烦,但使得将特权信息泄漏到非特权文件的可能性大大降低(因为您必须显式“泄漏”每条信息)。
privileged.sh
:
echo "Privileged user: $(whoami)"
su - somebody <<'EOF'
%unprivileged.sh%
EOF
unprivileged.sh
:
echo "Unprivileged user: $(whoami)"
preprocessor.sh
:
while IFS= read -r line
do
if [[ $line =~ ^%([^%]*)%$ ]]
then
cat "${BASH_REMATCH[1]}"
else
printf '%s\n' "$line"
fi
done < privileged.sh > program.sh
测试运行:
$ bash preprocessor.sh
$ sudo bash program.sh
Privileged user: root
Unprivileged user: somebody