为什么 sudoers 只允许我为 ALL 设置 NOPASSWD?

为什么 sudoers 只允许我为 ALL 设置 NOPASSWD?

我的情况是这样的:我试图让 www-data 用户能够 sudo 执行一些 shell 脚本,这样我就可以让我的 web 服务器上的页面显示系统信息(在 PHP 中使用 shell_exec() )。为此,我使用以下行编辑了我的 sudoers 文件

www-data ALL=(ALL:ALL) NOPASSWD: /home/evermind/scripts/*

让 Apache 能够运行该目录中的脚本,而无需输入 suoo 密码。不幸的是,这不起作用,指定具体的该目录中的脚本。shell_exec 无法执行该命令,并出现以下错误:

sudo:没有 tty 存在并且没有指定 askpass 程序

这就是事情变得……奇怪的地方。如果我用“ALL”替换路径规范,那么一切都会正常工作。为什么会这样?有什么原因我不能为单个文件或目录指定 NOPASSWD 吗?

出于安全原因,我非常不愿意允许 www-data 自由控制一切,尽管 Web 应用程序非常安全,并且没有明显的方式可以执行任意命令。

答案1

只使用目录路径而不使用通配符来添加怎么样?

www-data ALL=(ALL:ALL) NOPASSWD: /home/evermind/scripts/

根据sudoers手册页:

A Cmnd_List is a list of one or more
commandnames, directories, and 
other aliases. ... A directory is a fully 
qualified path name ending in a '/'. 
When you specify a directory in a 
Cmnd_List, the user will be able to 
run any file within that directory (but 
not in any subdirectories therein).

答案2

好吧,离开这个问题一天再回来之后,我似乎或多或少解决了我自己的问题。

以前,我通过 shell_exec() 执行的终端命令是

sudo sh <path to my script>

今天,或多或少只是为了尝试某物,我修改了脚本的 chmod 使其可以直接执行。然后,我将 shell_exec() 字符串更改为

sudo <path to my script>

瞧,它开始工作了。逻辑似乎表明罪魁祸首实际上是 sh 实用程序声明,因为这是命令中的关键区别。不过,如果有人知道这到底是怎么回事,我会非常感兴趣。

答案3

理想情况下,如果您要自定义可以通过哪些命令运行,sudo则应在单独的文件中进行这些更改,/etc/sudoers.d/而不是sudoers直接编辑文件。您还应始终使用visudo来编辑文件。您永远不应授予NOPASSWD命令ALL

例子: sudo visudo -f /etc/sudoers.d/myWebScript

插入授予权限的行: www-data ALL= NOPASSWD: /home/evermind/scripts/

如果您想要限制,则调用它的方式具体是针对sh您将使用的目录: www-data ALL= NOPASSWD: /bin/sh /home/evermind/scripts/

我不确定为什么这些脚本需要sudo访问权限,通常您只需chmod o+x scriptname.sh确保它们位于用户拥有的目录中即可www-data

然后保存并退出,visudo如果有任何语法错误,它会警告您。

您可以运行sudo -l来查看您的用户已被授予的权限,如果任何用户特定的NOPASSWD命令出现%groupyouarein ALL=(ALL) ALL在输出中的任何命令之前,系统将提示您输入密码。

如果您发现自己创建了大量这样的 sudoers.d 文件,那么您可能希望按用户命名这些文件,以便更容易查看。请记住,文件名和文件内规则的顺序非常重要,最后加载的那个文件获胜,无论它比前面的条目更宽松还是更宽松。

您可以使用 00-99 或 aa/bb/cc 前缀来控制文件名排序,但请记住,如果您有任何文件没有数字前缀,它们将在编号文件之后加载,从而覆盖设置。这是因为根据您的语言设置,shell 使用的“词汇排序”首先对数字进行排序,然后在按“升序”排序时可能交错大小写。

尝试运行printf '%s\n' {{0..99},{A-Z},{a-z}} | sortprintf '%s\n' {{0..99},{A-Z},{a-z}} | LANG=C sort查看您当前的语言是否可以打印AaBbCc等,然后ABC确定abc要使用的最佳“最后一个”字母前缀是什么。

相关内容