2

运行 Fedora 9/10、Apache 2、PHP 5...

我可以使用 exec() 从 PHP 脚本以 root 身份运行 shell 脚本吗?

我是否只是给 Apache root 权限,然后在它们前面添加“sudo”命令?

具体来说,我正在尝试启动和停止后台脚本。

目前我有一个 shell 脚本,它只运行应用程序 start.sh:

#!/bin/bash 
/path/to/my/app/appname

还有一个杀死应用程序的脚本,stop.sh:

#!/bin/bash 
killall appname

我会这样做:

<?php
exec("sudo start.sh");
?>

提前致谢。

4

7 回答 7

13

你不能只是 sudo 那样,你需要先在 /etc/sudoers 文件中设置无密码 sudo。例如,这可以使用 visudo 命令来完成。确保您在 sudoers 文件中设置权限以将 apache 用户限制为您希望运行的单个命令(即您的 shell 脚本)。

即使这样,它也会带来安全风险,因为任何人都可以创建 PHP 脚本并依次运行您的 shell 脚本。因此,请确保 shell 脚本本身不会被 Apache 用户更改。

第二部分killall问题更大。您不应该只允许 Apache 以 root 权限运行 killall。您应该将 killall 包装在另一个 shell 脚本中,并在 sudoers 中授予对它的访问权限。

最后:不要用root帐户运行Apache,不要使用setuid。两者都会打开一罐蠕虫,并且由于您是新手(鉴于您提出的问题),您很可能会错过一些会造成潜在问题的小细节。

于 2009-04-06T16:38:08.950 回答
4
  1. 不要将 Apache 作为root. Apache 的设计初衷就是很好地应对从 as 开始root,然后尽快放弃它的权限

  2. 也不要sudo在您的脚本中使用 - 很容易导致sudo配置错误,以至于在您的服务器上运行的任何脚本都可以使用root特权运行它喜欢的任何程序

  3. 看看让你自己的程序运行“setuid”,这样它就获得了 root 权限,但是当它不再需要它们时就放弃它们(就像 Apache 一样)

  4. 确保您的“setuid”可执行文件不能由不应该运行它的任何人运行。

于 2009-04-06T16:39:21.303 回答
3

我不是这个领域的专业人士,但看起来你需要 SUID 标志。

在此处阅读示例或谷歌

于 2009-04-06T16:29:39.797 回答
2

您至少需要一个抽象层来提供一点安全性!...

我这样做的方法是在 Python 中使用 root privs 编写一个简单的 UDP 服务器*,它: 监视给定端口上的传入 UDP 数据包 如果它们匹配,则将它们与白名单进行比较 执行操作

然后你有一点 PHP 用预定义的消息向 Python 服务器发送消息......

<?php
  $handle = fsockopen("udp://localhost",12345);
  fwrite($handle,"Start Script");
  fclose($handle);
?>

python 服务器监视端口 12345 上的数据包,但忽略任何不是“启动脚本”或“停止脚本”的数据包,因为它以 root 身份运行,它可以愉快地启动您的 bash 脚本。但是,您绝对必须使用白名单,将任何输入从 UDP 套接字直接发送到命令行是非常不安全的!

请注意,UDP 可以被欺骗,因此如果您的防火墙允许欺骗的入站流量(它真的不应该!)有人可能会向您的 Python 服务器发送伪造的数据包并停止/启动您的服务。这不太可能成为问题,但是如果您无法修复防火墙并且想要防范它,您可以使用无法被欺骗的 TCP/IP 来修改上述内容。

罗杰·希思科特。

*这是一个非常简单的服务器(约 20 行),但如果您不知道如何发送,请给我发消息,我会将其发送给您或在此处发布。

于 2009-04-06T17:38:50.847 回答
2

你不想给 Apache root。

您的问题还有另一种解决方案。问题是 Apache 无法终止该进程,因为它由 root 拥有。您可以做的是将所有者更改为“www-data”,这是 Apache 的标识。

如果该进程是一项服务并在启动时启动,您可以添加

sudo -u www-data <start-up script>

这样 www-data 将成为该进程的所有者,因此运行关闭脚本将起作用。

于 2012-10-30T03:25:14.353 回答
1

根据要求,这是python服务器......

#!/usr/bin/python
import os 
import socket
print "  Loading Bindings..."
settings = {}
line = 0 
for each in open('/path/to/actions.txt', 'r'):
 line = line + 1
  each = each.rstrip()
  if each <> "":
    if each[0] <> '#':
      a = each.partition(':')
      if a[2]:
        settings[a[0]] = a[2]
      else:
        print "    Err @ line",line,":",each
print "  Starting Server...",
port = 12345
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", port))
print "OK."
print "  Listening on port:", port
while True:
    datagram = s.recv(1024)
    if not datagram:
        break
    print "Rx Cmd:", datagram
    if settings.has_key(datagram):
      print "Launch:", settings[datagram]
      os.system(settings[datagram]+" &")
s.close() 

配置文件“actions.txt”使用格式“action-name:corresponding-shell-command”,即

# Hash denotes a comment
webroot:nautilus /var/www
ftp:filezilla
edit_homepage:gedit /var/www/homepage/htdocs/index.php

此代码不会检查传入 UDP 数据包的原始 IP,因为我在 localhost 上运行它,我受到其他任何人的防火墙保护,并且无论如何检查都不会提供针对欺骗的保护。

我没有时间重写它以使用 TCP/IP,但 Python 是一种值得了解的语言,所以如果你真的想要那个功能,我会留给你一个 google 来搜索“Python”和“SOCK_STREAM” . 不过,这可能不值得您费心,配置防火墙更容易,这样就不会受到欺骗的本地主机数据包可以通过并修改代码以确保它只侦听来自环回的数据包。

于 2009-04-07T06:59:59.487 回答
1

您可以考虑使用与具有 root 权限的帐户的 keepair 身份验证的 ssh 连接到 localhost。在这样的设置中,您的网络服务器不需要 root 访问权限。

于 2013-08-22T10:57:12.013 回答