9

我目前正在做一个项目,用 PHP 对系统进行更改(例如更改 Nginx 的配置文件/重新启动服务)。

PHP 脚本在 localhost 上运行。在我看来,最好的(阅读:最安全的)方法是使用 SSH 建立连接。我考虑以下选项之一:

选项 1:在 php 会话中存储用户名/密码并提示输入 sudo

使用带有用户名/密码的 phpseclib,将这些值保存在 php 会话中,并为每个命令提示输入 sudo。

选项 2:使用 root 登录

在登录脚本中使用带有 root 用户名和密码的 phpseclib。在这种情况下,您不必向用户询问 sudo。(不是真正安全的解决方案)

<?php
include('Net/SSH2.php');

$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('root', 'root-password')) {
    exit('Login Failed');
}
?>

选项 3:使用从文件中读取的公钥进行身份验证

使用带有公钥的 PHP SSHlib 进行身份验证并将公钥放在 www 根目录之外。

<?php

    $connection = ssh2_connect('shell.example.com', 22, array('hostkey' => 'ssh-rsa'));
    if (ssh2_auth_pubkey_file($connection, 'username', '/home/username/.ssh/id_rsa.pub', '/home/username/.ssh/id_rsa', 'secret')) {
        echo "Public Key Authentication Successful\n";
    } else {
        die('Public Key Authentication Failed');
    }
?>

选项 4:?

4

6 回答 6

11

我建议您通过 3 个简单的步骤执行此操作:

第一的。 创建另一个用户(例如runner)并使您的敏感数据(如用户/通行证、私钥等)仅供该用户访问。换句话说,拒绝您的 php 代码访问这些数据。

第二。 之后,创建一个简单的阻塞 fifo 管道并授予您的 php 用户写入权限。

最后的。 最后编写一个简单的守护进程来从 fifo 读取行并执行它,例如通过 ssh 命令。使用用户运行此守护程序runner

要执行命令,您只需将命令写入文件(fifo 管道)。如果需要,可以将输出重定向到另一个管道或一些简单的文件中。

要使 fifo 使用这个简单的命令:

mkfifo "FIFONAME"

runner 守护进程将是一个简单的 bash 脚本,如下所示:

#!/bin/bash
while [ 1 ]
do
    cmd=$(cat FIFONAME | ( read cmd ; echo $cmd ) )
    # Validate the command
    ssh 192.168.0.1 "$cmd"
done

在此之后,您可以信任您的代码,如果您的 php 代码完全被黑,您的上游服务器仍然是安全的。在这种情况下,攻击者根本无法访问您的敏感数据。他可以向您的runner守护进程发送命令,但如果您正确验证命令,则无需担心。

:-)

于 2012-11-27T15:05:42.913 回答
1

方法一

我可能会使用suid 标志。用 C编写一个小suid 包装器,并确保它执行的所有命令都是预定义的,并且不能由您的 php 脚本控制。因此,您创建包装器并从 ARGV 获取命令。所以一个电话可能看起来像这样:

./wrapper reloadnginx

Wrapper 然后执行/etc/init.d/nginx reload.

确保你chown包装到 root 和chmod +s. 然后它将以 root 身份生成命令,但由于您预定义了所有命令,因此您的 php 脚本不能以 root 身份执行任何其他操作。

方法二

使用 sudo 并将其设置为对某些命令进行无密码执行。这样您就可以达到相同的效果,并且只能以 root 身份生成某些应用程序。但是,您无法控制参数,因此请确保这些二进制文件中没有特权升级。

您真的不想为 PHP 脚本提供完全的 root 访问权限。

于 2012-11-28T09:45:44.030 回答
0

如果您在同一台主机上运行,​​我建议直接编写配置文件并(重新)启动服务或编写包装脚本。

第一个选项显然需要非常高的权限级别,我不建议这样做。但是,这将是最简单的实现。您使用 ssh 的其他命名选项没有多大帮助,因为可能的攻击者仍然可以轻松获得 root 权限

第二种选择更安全,涉及编写具有高级访问权限的程序,该程序仅接受指定的输入文件,例如来自目录。php-script 只是用户的前端,将编写所述输入文件,因此只需要非常低的权限。这样,您就可以将高权限和低权限分开,从而降低风险,因为保护程序更容易,可能的攻击者只能通过文本文件间接使用该程序。此选项需要更多工作,但更安全。

于 2012-11-20T11:24:43.577 回答
0

您可以扩展选项 3 并在没有任何库的情况下使用 SSH 密钥

$command = sprintf('ssh -i%s -o "StrictHostKeyChecking no" %s@%s "%s"',
                $path, $this->getUsername(), $this->getAddress(), $cmd );
return shell_exec( $command );

我在我的项目中经常使用它。您可以查看我创建的SSH 适配器。

上面的问题是您无法做出实时决策(连接到服务器时)。如果您需要实时尝试名为SSH2的 PHP 扩展。

附言。我同意你的看法。SSH 接缝是最安全的选择。

于 2012-11-26T15:05:08.660 回答
0

您可以使用setcap允许 Nginx 绑定到端口 80/443,而无需以 root 身份运行。Nginx 只需以 root 身份运行即可绑定端口 80/443(任何小于 1024 的端口)。此答案setcap中有详细说明。

不过有一些注意事项。您必须将chown日志文件发送给正确的用户 ( ),并将 pid 文件配置为( )chown -R nginx:nginx /var/log/nginx以外的其他位置。/var/run/pid /path/to/nginx.pid

lawl0r 为 setuid/sudo 提供了一个很好的答案。

作为最后的恢复,如果配置已更改,您可以使用 cron 作业定期重新加载配置。

无论哪种方式,当它在同一个系统上时,您都不需要 SSH。

于 2012-11-30T18:17:42.410 回答
-1

哥们,这完全错了。

您不想更改任何要创建新文件的配置文件,然后将它们包含在默认配置文件中。

apache 的示例,您有 *.conf 文件和包含指令。更改默认配置文件是完全疯狂的。我就是这样做的。

您不需要 ssh 或类似的东西。

相信我,如果你愿意,它会更好、更安全。

于 2012-11-27T18:09:47.940 回答