如何让 PHP 脚本以 root 身份运行 shell 脚本?

发布于 2024-07-16 06:56:08 字数 460 浏览 4 评论 0 原文

运行 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");
?>

提前致谢。

Running Fedora 9/10, Apache 2, PHP 5...

Can I run a shell script as root, from a PHP script using exec()?

Do I just give Apache root priveleges, and then add "sudo" in front of them command?

Specifically, I'm trying to start and stop a background script.

Currently I have a shell script that just runs the app, start.sh:

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

And a script that kills the app, stop.sh:

#!/bin/bash 
killall appname

Would I just do:

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

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

预谋 2024-07-23 06:56:08

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

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

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

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

You can't just sudo like that, you need to setup passwordless sudo first in /etc/sudoers file. This can be done with visudo command for example. Make sure you set up privileges in sudoers file in such way to constrain the apache user to that single command you wish to run (i.e. your shell script).

Even then, it poses a security risk, because anyone could create a PHP script and run your shell script in turn. So make sure that shell script itself is secure from alteration by Apache user.

The second part, killall, is even more problematic. You shouldn't just allow Apache to run killall with root privileges. You should wrap killall in another shell script and grant access to that in sudoers.

In the end: do not run Apache with root account and do not use setuid. Both open a can of worms, and since you are a newbie (given the question you asked) you are very likely to miss some of small details that would create potential problems.

清醇 2024-07-23 06:56:08
  1. 不要以 root 身份运行 Apache。 Apache 的设计能够很好地应对以 root 身份启动,然后尽快放弃其特权

  2. 也不要在脚本中使用 sudo -很容易导致 sudo 配置错误,这样服务器上运行的任何脚本都可以使用 root 权限运行任何程序

  3. 考虑让您自己的程序运行“setuid”,以便它获得 root 权限,然后在不再需要它们时删除它们(就像 Apache 所做的那样)< /p>

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

  1. Don't run Apache as root. Apache has been designed to cope very well with starting as root and then dropping its privileges just as soon as it can

  2. Don't use sudo within your script either - it'll be too easy to end up with sudo misconfigured such that any script running on your server gets to run any program it likes with root privileges

  3. Look at making your own program run "setuid", so that it gets root privileges, but then drops them (just like Apache does) when it doesn't need them any more

  4. Make sure your "setuid" executable can't be run by anybody who isn't supposed to be able to run it.

夏日浅笑〃 2024-07-23 06:56:08

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

请阅读此处的示例或谷歌

I'm not professional in this field, but it looks like you need SUID flag.

Read here for examples or google

生生漫 2024-07-23 06:56:08

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

我这样做的方法是用 Python 编写一个带有 root 权限的简单 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 行),但如果您不知道如何编写,请给我发消息,我会将其发送给您或将其发布在这里。

You need a layer of abstraction to provide a little security at least!...

The way I do this is to write a simple UDP server* with root privs in Python which:
watches out for incoming UDP packets on a given port
compares them to a whitelist
if they match carry out the operation

You then have a little bit of PHP that messages the Python server with pre-defined messages...

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

The python server watches for packets on port 12345 but just ignores any that aren't either "Start Script" or "Stop Script", as it runs as root it can happily start your bash script. You ABSOLUTELY MUST use white-listing though, it is REALLY NOT SAFE to send ANY input from a UDP socket to the command line directly!

Do note that UDP can be spoofed so if your firewall permits spoofed inbound traffic (it realy ought not to!) someone could send forged packets to your Python server and stop/start your service. This is unlikely to be a problem but if you can't fix your firewall and you want to guard against it you could rework the above using TCP/IP which can't be spoofed.

Roger Heathcote.

*It's a really trivial server to write ( ~20 lines ) but if you don't know how to then just message me and I will send it to you or post it here.

薄荷梦 2024-07-23 06:56:08

您不想授予 Apache root 权限。

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

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

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

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

You don't want to give Apache root.

There's another solution to your problem. The problem is that Apache cannot kill the process because it is owned by root. What you can do is change the owner to 'www-data' which is what Apache is identified as.

If the process is a service and starts up on boot you can add the

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

so that www-data would be the owner of that process and hence running the shut-down script would work.

墨小墨 2024-07-23 06:56:08

根据要求,这里是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它在本地主机上运行,​​我受到其他任何人的防火墙的影响,并且检查无论如何都不会提供针对欺骗的保护。

我没有时间重写它以使用 TCP/IP,但 Python 是一种值得了解的语言,因此如果您确实想要该功能,我将让您在 google 上搜索“Python”和“SOCK_STREAM” 。 不过,这可能不值得您费心,配置防火墙更容易,这样欺骗性的本地主机数据包就无法通过并修改代码以确保它只侦听来自环回的数据包。

As requested, here's the python server...

#!/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() 

The config file "actions.txt" uses the format "action-name:corresponding-shell-command" i.e.

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

This code doesn't check the originating IP of the incoming UDP packets as I have it running on localhost, I am firewalled of from anyone else and checking would provide no protection against spoofing anyway.

I don't have time to rewrite it to use TCP/IP but Python is a language that's worth getting to know so if you really want that functionality I'll leave it to you to have a google for 'Python' and 'SOCK_STREAM'. It's probably not worth your trouble though, it's easier to configure your firewall so that no spoofed localhost packets can get through and modify the code to make sure it only listens to packets from the loopback.

再见回来 2024-07-23 06:56:08

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

You could consider using an ssh connection to localhost with keepair authentication to an account that has root permissions. In such a setup you won't need root access for your webserver.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文