允许PHP使用root权限执行bash脚本

时间:2022-03-27 01:12:11

how to allow a PHP script to execute a bash script with root permissions?

如何允许PHP脚本执行具有root权限的bash脚本?

Let's say there is a PHP script...

假设有一个PHP脚本......

<?php
// location: /var/www/script.php
exec("bash /var/scripts/test.sh"); // "sudo bash ..." does not work
?>

and a bash script ...

和一个bash脚本......

#!/bin/bash
# location: /var/scripts/test.sh
sudo mkdir /test

Of course PHP and Apache should not run as root and at best only the script can be executed with root permissions. Any ideas?

当然,PHP和Apache不应该以root身份运行,最多只能使用root权限执行脚本。有任何想法吗?

Best regards, Jimbo

最好的问候,Jimbo

6 个解决方案

#1


6  

Any PHP-based solution that gives root rights at some point of the chain is dangerous: An attacker with access to the PHP user could gain access to the root user, and that is unacceptable from a security point of view.

任何基于PHP的解决方案都会在链的某个位置提供root权限是危险的:有权访问PHP用户的攻击者可以访问root用户,从安全角度来看这是不可接受的。

I have never implemented this myself, but I'll suggest what I suggested here: Have a script/cron job with root rights frequently scan some location for a sign from the PHP script that a job is to be done - for example, a file with a certain name, or an entry in a jobs database.

我自己从来没有实现过这个,但是我会建议我在这里建议:拥有root权限的脚本/ cron作业经常扫描一些位置,从PHP脚本中找到要完成作业的符号 - 例如,一个文件具有特定名称或作业数据库中的条目。

If that file is found to exist, the root script does its thing, and removes the file again.

如果发现该文件存在,则根脚本会执行其操作,并再次删除该文件。

If your PHP script doesn't need direct response from the root script, I think this would be the best way to go. (A response could also be facilitated by the root script writing a status message into the file, of course).

如果您的PHP脚本不需要来自根脚本的直接响应,我认为这将是最好的方法。 (当然,根脚本将状态消息写入文件也可以促进响应)。

As long as you closely limit what kinds of jobs PHP can write for the root script to do, this is a watertight solution, as it doesn't get the root user into PHP's business.

只要您严格限制PHP可以为根脚本执行哪些类型的作业,这是一个防水的解决方案,因为它不会让root用户进入PHP的业务。

#2


6  

If don't want wait for cron, here is a simple wrapper in C, what you will call from php.

如果不想等待cron,这里有一个简单的C包装器,你将从php调用。

#include <unistd.h>
#include <errno.h>
#define WEBUID 500
main( int argc, char ** argv, char ** envp ) {
    if( getuid() != WEBUID ) exit(1);
    /* some more security checks */
    if( setuid(geteuid()) ) perror( "setuid error" );
    envp = 0; /* don't want environment - security problem */
    system( "/hardcoded/path/to/script.bash", argv, envp );
}

This compiled wrapper should be owned as root, group "www" and should have "s-bit".
chwon root.www wrapper; chmod 4440 wrapper, so

这个编译好的包装器应该被拥有为root,group“www”并且应该具有“s-bit”。 chwon root.www wrapper; chmod 4440包装,所以

  • when is executed his effective UID will be root
  • 执行时,他的有效UID将是root
  • execute it can only group www (web-server's group)
  • 执行它只能组www(网络服务器的组)
  • and when the UID of the caller is not a web-server will exit
  • 当调用者的UID不是Web服务器时,将退出

#3


2  

You need to take a look at incron (cron for file system events). Have the php write to a file and set incron to launch your script on closure of the written to file (incron is very specific). Your script should probably also sanitize the input file to prevent code injection and use the lockfile command as well to prevent any race conditions between multiple web users.

您需要查看incron(文件系统事件的cron)。让php写入文件并设置incron以在关闭写入文件时启动脚本(incron非常具体)。您的脚本可能还应该清理输入文件以防止代码注入,并使用lockfile命令以防止多个Web用户之间的任何竞争条件。

I have a mini-web interface where one can turn on anonymous FTP or other services on for 1 hour with a password. www runs with normal privilages as does www-data (the php user) but incron calls the input handling script as root.

我有一个迷你网络界面,人们可以使用密码打开匿名FTP或其他服务1小时。 www和普通的特权一样运行www-data(php用户),但incron以root身份调用输入处理脚本。

Mike

麦克风

#4


1  

You may not need PHP or Apache to run as root. If you have control of your server you might be able to use an Apache module called suPHP and specify the user you want to run Apache as for your php scripts in the config. You can do this on a site by site basis so you only need to run suPHP for scripts on a particular domain. I lack the expertise to advise you on how to install it, but I had our dedicated server company do it for me to allow a github post-receive hook to call a script on my dev server to trigger a git pull to the dev server any time someone pushes to the github repos. I was unable to get it to work any other way since Apache needs to run as the owner of the local repos for it to work.

您可能不需要PHP或Apache以root身份运行。如果您可以控制服务器,则可以使用名为suPHP的Apache模块,并在配置中指定要运行Apache的用户和PHP脚本。您可以逐个站点地执行此操作,因此您只需要为特定域上的脚本运行suPHP。我缺乏建议如何安装它的专业知识,但我有我们的专用服务器公司为我做这个允许github post-receive挂钩调用我的开发服务器上的脚本来触发git pull到开发服务器任何有人推送到github回购。我无法让它以任何其他方式工作,因为Apache需要作为本地存储库的所有者运行才能工作。

I just thought of another possible solution based on the other comments here -- you might be able to write a simple php script to receives the request from the github hook and write some arbitrary info to a file in a directory with 777 permissions or to the db. Then have a cron job that checks that file or db every minute to see if it has changed and if so, issue the git pull request directly since cron usually runs as root already. You could even just see if the file's timestamp has changed to determine whether to do the git pull. You could have your cron script su to whatever user owned the repos and issue the git pull then. Not a true realtime solution, but if the cron script is very simple it wouldn't really bog down your system to call it every minute or two. Hope that helps.

我刚刚想到了基于其他评论的另一种可能的解决方案 - 您可能能够编写一个简单的PHP脚本来接收来自github钩子的请求并将一些任意信息写入具有777权限的目录中的文件或者D b。然后有一个cron作业,每分钟检查一次该文件或db以查看它是否已更改,如果是,则直接发出git pull请求,因为cron通常以root身份运行。您甚至可以查看文件的时间戳是否已更改以确定是否执行git pull。您可以将您的cron脚本su添加到拥有repos的任何用户,然后发出git pull。这不是一个真正的实时解决方案,但如果cron脚本非常简单,它不会让您的系统陷入困境,每隔一两分钟就会调用它。希望有所帮助。

#5


0  

Use a daemon running as root (maybe written in C), which starts the shell scripts for you. To trigger shell script execution from within the PHP script just use IPC (message queues).

使用以root身份运行的守护程序(可能用C编写),它会为您启动shell脚本。要从PHP脚本中触发shell脚本执行,只需使用IPC(消息队列)。

Have a look here to get an idea what I am talking about: http://php.net/manual/en/function.msg-send.php#114831

看看这里,了解我在说什么:http://php.net/manual/en/function.msg-send.php#114831

#6


0  

I recently published a project that allows PHP to obtain and interact with a real Bash shell (as root if requested), it solves the limitations of exec() and shell_exec(). Get it here: https://github.com/merlinthemagic/MTS

我最近发布了一个项目,允许PHP获取真正的Bash shell并与之交互(如果需要,可以作为root),它解决了exec()和shell_exec()的限制。在此处获取:https://github.com/merlinthemagic/MTS

After downloading you would simply use the following code:

下载后,您只需使用以下代码:

$shell    = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1  = $shell->exeCmd('/my/bash/script.sh');
//the return will be a string containing the return of the command
echo $return1;

In terms of security it is far better than running apache as root. But letting PHP anywhere near root is always tricky.

在安全性方面,它比以root身份运行apache要好得多。但让PHP靠近root位置总是很棘手。

The project i built achieves a root bash shell in one of 2 ways:

我构建的项目通过以下两种方式之一实现了root bash shell:

1) You allow apache the right to sudo python.

1)你允许apache权限sudo python。

OR

要么

2) You pass root credentials to the object every time you need a shell with root setup.

2)每次需要具有root设置的shell时,都会将根凭据传递给对象。

Pick your poison. :) Read the documentation.

选择你的毒药。 :)阅读文档。

#1


6  

Any PHP-based solution that gives root rights at some point of the chain is dangerous: An attacker with access to the PHP user could gain access to the root user, and that is unacceptable from a security point of view.

任何基于PHP的解决方案都会在链的某个位置提供root权限是危险的:有权访问PHP用户的攻击者可以访问root用户,从安全角度来看这是不可接受的。

I have never implemented this myself, but I'll suggest what I suggested here: Have a script/cron job with root rights frequently scan some location for a sign from the PHP script that a job is to be done - for example, a file with a certain name, or an entry in a jobs database.

我自己从来没有实现过这个,但是我会建议我在这里建议:拥有root权限的脚本/ cron作业经常扫描一些位置,从PHP脚本中找到要完成作业的符号 - 例如,一个文件具有特定名称或作业数据库中的条目。

If that file is found to exist, the root script does its thing, and removes the file again.

如果发现该文件存在,则根脚本会执行其操作,并再次删除该文件。

If your PHP script doesn't need direct response from the root script, I think this would be the best way to go. (A response could also be facilitated by the root script writing a status message into the file, of course).

如果您的PHP脚本不需要来自根脚本的直接响应,我认为这将是最好的方法。 (当然,根脚本将状态消息写入文件也可以促进响应)。

As long as you closely limit what kinds of jobs PHP can write for the root script to do, this is a watertight solution, as it doesn't get the root user into PHP's business.

只要您严格限制PHP可以为根脚本执行哪些类型的作业,这是一个防水的解决方案,因为它不会让root用户进入PHP的业务。

#2


6  

If don't want wait for cron, here is a simple wrapper in C, what you will call from php.

如果不想等待cron,这里有一个简单的C包装器,你将从php调用。

#include <unistd.h>
#include <errno.h>
#define WEBUID 500
main( int argc, char ** argv, char ** envp ) {
    if( getuid() != WEBUID ) exit(1);
    /* some more security checks */
    if( setuid(geteuid()) ) perror( "setuid error" );
    envp = 0; /* don't want environment - security problem */
    system( "/hardcoded/path/to/script.bash", argv, envp );
}

This compiled wrapper should be owned as root, group "www" and should have "s-bit".
chwon root.www wrapper; chmod 4440 wrapper, so

这个编译好的包装器应该被拥有为root,group“www”并且应该具有“s-bit”。 chwon root.www wrapper; chmod 4440包装,所以

  • when is executed his effective UID will be root
  • 执行时,他的有效UID将是root
  • execute it can only group www (web-server's group)
  • 执行它只能组www(网络服务器的组)
  • and when the UID of the caller is not a web-server will exit
  • 当调用者的UID不是Web服务器时,将退出

#3


2  

You need to take a look at incron (cron for file system events). Have the php write to a file and set incron to launch your script on closure of the written to file (incron is very specific). Your script should probably also sanitize the input file to prevent code injection and use the lockfile command as well to prevent any race conditions between multiple web users.

您需要查看incron(文件系统事件的cron)。让php写入文件并设置incron以在关闭写入文件时启动脚本(incron非常具体)。您的脚本可能还应该清理输入文件以防止代码注入,并使用lockfile命令以防止多个Web用户之间的任何竞争条件。

I have a mini-web interface where one can turn on anonymous FTP or other services on for 1 hour with a password. www runs with normal privilages as does www-data (the php user) but incron calls the input handling script as root.

我有一个迷你网络界面,人们可以使用密码打开匿名FTP或其他服务1小时。 www和普通的特权一样运行www-data(php用户),但incron以root身份调用输入处理脚本。

Mike

麦克风

#4


1  

You may not need PHP or Apache to run as root. If you have control of your server you might be able to use an Apache module called suPHP and specify the user you want to run Apache as for your php scripts in the config. You can do this on a site by site basis so you only need to run suPHP for scripts on a particular domain. I lack the expertise to advise you on how to install it, but I had our dedicated server company do it for me to allow a github post-receive hook to call a script on my dev server to trigger a git pull to the dev server any time someone pushes to the github repos. I was unable to get it to work any other way since Apache needs to run as the owner of the local repos for it to work.

您可能不需要PHP或Apache以root身份运行。如果您可以控制服务器,则可以使用名为suPHP的Apache模块,并在配置中指定要运行Apache的用户和PHP脚本。您可以逐个站点地执行此操作,因此您只需要为特定域上的脚本运行suPHP。我缺乏建议如何安装它的专业知识,但我有我们的专用服务器公司为我做这个允许github post-receive挂钩调用我的开发服务器上的脚本来触发git pull到开发服务器任何有人推送到github回购。我无法让它以任何其他方式工作,因为Apache需要作为本地存储库的所有者运行才能工作。

I just thought of another possible solution based on the other comments here -- you might be able to write a simple php script to receives the request from the github hook and write some arbitrary info to a file in a directory with 777 permissions or to the db. Then have a cron job that checks that file or db every minute to see if it has changed and if so, issue the git pull request directly since cron usually runs as root already. You could even just see if the file's timestamp has changed to determine whether to do the git pull. You could have your cron script su to whatever user owned the repos and issue the git pull then. Not a true realtime solution, but if the cron script is very simple it wouldn't really bog down your system to call it every minute or two. Hope that helps.

我刚刚想到了基于其他评论的另一种可能的解决方案 - 您可能能够编写一个简单的PHP脚本来接收来自github钩子的请求并将一些任意信息写入具有777权限的目录中的文件或者D b。然后有一个cron作业,每分钟检查一次该文件或db以查看它是否已更改,如果是,则直接发出git pull请求,因为cron通常以root身份运行。您甚至可以查看文件的时间戳是否已更改以确定是否执行git pull。您可以将您的cron脚本su添加到拥有repos的任何用户,然后发出git pull。这不是一个真正的实时解决方案,但如果cron脚本非常简单,它不会让您的系统陷入困境,每隔一两分钟就会调用它。希望有所帮助。

#5


0  

Use a daemon running as root (maybe written in C), which starts the shell scripts for you. To trigger shell script execution from within the PHP script just use IPC (message queues).

使用以root身份运行的守护程序(可能用C编写),它会为您启动shell脚本。要从PHP脚本中触发shell脚本执行,只需使用IPC(消息队列)。

Have a look here to get an idea what I am talking about: http://php.net/manual/en/function.msg-send.php#114831

看看这里,了解我在说什么:http://php.net/manual/en/function.msg-send.php#114831

#6


0  

I recently published a project that allows PHP to obtain and interact with a real Bash shell (as root if requested), it solves the limitations of exec() and shell_exec(). Get it here: https://github.com/merlinthemagic/MTS

我最近发布了一个项目,允许PHP获取真正的Bash shell并与之交互(如果需要,可以作为root),它解决了exec()和shell_exec()的限制。在此处获取:https://github.com/merlinthemagic/MTS

After downloading you would simply use the following code:

下载后,您只需使用以下代码:

$shell    = \MTS\Factories::getDevices()->getLocalHost()->getShell('bash', true);
$return1  = $shell->exeCmd('/my/bash/script.sh');
//the return will be a string containing the return of the command
echo $return1;

In terms of security it is far better than running apache as root. But letting PHP anywhere near root is always tricky.

在安全性方面,它比以root身份运行apache要好得多。但让PHP靠近root位置总是很棘手。

The project i built achieves a root bash shell in one of 2 ways:

我构建的项目通过以下两种方式之一实现了root bash shell:

1) You allow apache the right to sudo python.

1)你允许apache权限sudo python。

OR

要么

2) You pass root credentials to the object every time you need a shell with root setup.

2)每次需要具有root设置的shell时,都会将根凭据传递给对象。

Pick your poison. :) Read the documentation.

选择你的毒药。 :)阅读文档。