从PHP脚本更改Linux用户密码

6
我有一个“简单”的问题:如何在PHP脚本内安全地更改用户密码,而不授予Apache root权限或引入其他疯狂的安全漏洞?
背景: CentOS 6,Apache 2.2.13,PHP 5.3.3
我知道pam_chpasswd()命令,它是PECL PAM库的一部分。但是,除非主机进程(httpd)对/etc/shadow文件具有读取访问权限,否则此函数将失败。(坏主意!如果需要这么高的特权,不确定这个库如何帮助……)
据我所见,理想的情况是让PHP使用'sudo -u [更改密码的用户名]'调用shell脚本 这将以用户身份“运行”脚本,因此他应该有更改自己密码的权限。并且sudo将要求用户提供现有密码以进行身份验证,从而防止一个用户更改另一个用户的密码。
但出现了问题…在使用popen打开进程时,进程永远不会执行。我已经设置了Shell脚本,将一些文本转储到/tmp中的公共可写文件中。但是它从未达到那个点。
$cmd = "/usr/bin/sudo -S -u$username /file_to_execute.sh";
$handle = popen ($cmd, "w");   // Open the process for writing
fwrite ($handle, "$current_password\n");  // Send the user's current password to sudo (-S option)
fwrite  .... (write the username, current password, and new password, so the script can change it)
$result = pclose($handle);

如果我访问这个php脚本(http://server/script.php),函数会立即失败,$result = 1。
如果我修改sudoers文件(visudo)并添加一行:
$Defaults:apache !requiretty
脚本会冻结大约10秒钟,然后失败($result = 1)。
非常感谢您提供任何建议!

这些都可以吗?https://dev59.com/9EXRa4cB1Zd3GeqPqUm4?rq=1 - aknosis
2个回答

2
为了达到以上目的并确保安全,建议使用expect或将Apache用户添加到具有对该文件的写访问权限且仅限于该文件的组中。
使用expect时,您需要包括您的sudo密码,因为它将监听来自操作系统的Password:响应,并在看到时自动回复sudo密码。这将允许您将shell_exec()和相关函数与expect配合使用以实现结果。
出于安全考虑,我会选择第二种路线,即使用组权限将写入文件的权限分配给仅具有对该文件的写访问权限的组。
例如:
groupadd secure_apache
usermod -G secure_apache apache_user
chown owner:secure_apache /tmp/file_to_change
chmod 740 /tmp/file_to_change

#2在多用户环境下能工作吗?即多个用户同时尝试更改密码?我假设每个密码更改请求都必须创建一个随机命名的文件,以防止用户在过程中互相干扰...? - Ryan Griggs
1
如果您选择第二个选项,您可以实现 flock() 来在第一个用户尝试时锁定文件。当他们完成后,删除 flock(),其他用户就可以继续了。至少其他用户会收到一个无法在此时进行的错误提示。 - Mike Mackintosh
我使用popen访问sudo的STDIN从来没有成功过。不过看看这个... https://dev59.com/9EXRa4cB1Zd3GeqPqUm4 - Mike Mackintosh

0
更安全的方法是将用户名和密码存储在一个特殊目录中的文件中,然后让cron定时执行(每分钟一次)。

感谢您的回答。然而,这会引入两个问题: 1)用户无法立即获得有关密码是否更改的反馈。 2)用户现有的密码未经验证。看起来这可能不太安全。我希望要求用户提供其现有密码才能更改密码。这可以防止任何一位用户劫持更改另一位用户的密码。 - Ryan Griggs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接