万能脚本助Web执行底层Linux命令

需求分析:

这里先要说明的是,这一篇不是QT系列的文章,而是关于Web的,之所以要写这篇,是因为以前做Web相关开发的时候,经常涉及到与linux底层命令打交道,比如说创建一个目录,删除一个目录,或者是执行一个自定义的脚本。关于PHP如何调用、执行Linux的底层命令,以前也研究过,基本上实现了自己需要的功能,但是有些地方一直没有弄明白。今天又偶然碰到了,趁着这个机会向大家描述一下一步一步应该如何实现,并最后附上相关C代码。

原理实现:

首先,一般搭建的Web站点都是采用Apache或Nginx,因此当使用php执行linux的命令的时候,在linux端体现出的时Apache或Nginx用户的身份来执行的。通常情况下基于安全考虑,Apache或Nginx在linux端的默认用户是不具有很高的权限的,比如删除、创建等,因此我们必须通过一种方式,为其赋予一定的权限。在我以前写过的文章中,我采用了一种方法,即将Apache或Nginx的默认用户修改了,给那个用户赋予了很高的权限,虽然达到了我的目的,但是恰恰造成了最大的隐患,即:web服务器默认用户权限设置过大,很容易受到来自外界的攻击,甚至不用外界,我自己在php端执行一个命令能将我整个站点删除掉,而在linux端对此基本没有任何防御能力。基于此,我们提出一种方式,在linux端不修改web服务器默认用户的权限,而是当执行命令时由我们来自己控制这条命令应当具有何种用户的执行权限,或者root用户,或者普通用户完全由我们传递的参数决定。

其次,基于上面的阐述,基本实现思路为:接受php传递来的username和passwd的参数,在linux端新建一个进程,然后将该进程模拟为一个用户的身份,即设置该进程的用户实际、有效的用户ID和用户组ID,然后再执行某条命令,此时执行该命令的过程就好像username用户本身执行那条命令一样。username能执行的有效命令只能在自己的职权范围之内,比如:如果username是普通用户,则它无法通过执行命令删除其他用户或root用户的文件。这样,在一定程度上实现了安全的可控性。

最后,根据上面提出的改变某个进程的实际、有效用户ID和用户组ID需要用到setuid()和setgid(),而关于这两个函数这里还有需要注意的地方,如果执行它的是特权用户,即root,则它可以任意设置自己的uid和gid,即可以模拟任意用户;而如果执行它的时普通用户,则它只能设置自己的uid和gid,而不能设置为其它用户的,即无法模拟其它用户。为了解决这个问题就要用到linux的一些特性,即设置文件的用户标记位:s,使文件在执行时具有文件所有者的权限。这样,Apache或Nginx默认用户执行这个文件的时候就类似于该文件的所有者在执行它,而我们利用root用户创建该文件,就相当于root用户在执行该文件,此时setuid和setgid就可以将进程模拟为任何用户的身份了。

实现代码:

[cpp] view plaincopy

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <pwd.h>
  8. #include <math.h>
  9. #include <time.h>
  10. //Usage: exefile   command    work_directory   username    password
  11. int main(int argc, char *argv[])
  12. {
  13. char *username = NULL;
  14. char *password = NULL;
  15. char *command  = NULL;
  16. char *workdir = NULL;
  17. struct passwd *stpasswd =   NULL;
  18. if(argc == 5)
  19. {
  20. command   = argv[1];
  21. workdir   = argv[2];  //work directory
  22. username  = argv[3];
  23. password  = argv[4];
  24. }
  25. else
  26. {
  27. return 1;
  28. }
  29. //printf("username = %s\n",username);
  30. //printf("password = %s\n",password);
  31. //printf("workdir = %s\n",workdir);
  32. //printf("command = %s\n",command);
  33. int result = 0;//auth(username,password);     //Ensure the user is a legel user in the system
  34. if(result == 0)  //auth successfully
  35. {
  36. int kidstatus, deadpid;
  37. //! fork()克隆出一个完全相同的进程出来;它会复制当前进程的所有变量,就好像一个进程克隆出来另一个一样
  38. //! fork()函数的返回值有三种情况:=0代表克隆出来的那个进程  >0代表“父”进程   <0 执行出错
  39. //! 这种情况一般就是fork出来新的进程,【可选:进行身份切换】,然后利用它来执行execlp(),执行相关的命令
  40. pid_t kidpid = fork();
  41. if (kidpid == -1)
  42. {
  43. printf("fork error");
  44. return 1;
  45. }
  46. if (kidpid == 0)
  47. {
  48. //! getpwnam():获取用户登录相关的信息
  49. //! 头文件:#include <pwd.h> #include <sys/types.h>
  50. stpasswd = getpwnam(username);
  51. //! setgid():设置实际用户组ID和有效用户组ID
  52. //! setuid():设置实际用户ID和有效用户ID
  53. //! chdir() : 修改当前目录
  54. //! 注意:如果是一个非特权用户,则它执行setgid和setuid只能设置为自己的gid和uid,而不能设置其它任何数值
  55. //! 如果是一个特权用户(即:拥有root权限),则可以利用setgid和setuid设置为任意数值,这也就是为什么最终
  56. //! 编译出来的文件要通过:chmod u+s 设置特权位
  57. setgid( (int)(stpasswd->pw_gid));   //Set current usergroup
  58. setuid( (int)(stpasswd->pw_uid));   //Set current user
  59. chdir(workdir);                                         //change work directory
  60. //! int execlp(const char *file, const char *arg, ..., (char *)0);
  61. //! execlp()会从PATH环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后
  62. //! 将第二个参数以后的参数当作该文件的argv[0], argv[1] ...,最后一个参数必须用空指针(NULL)结束
  63. //! 下面的命令就是:/bin/bash -c command执行
  64. int rv = execlp("/bin/bash", "/bin/bash", "-c", command, NULL);
  65. fflush(stdout);
  66. return rv;
  67. }
  68. //! we only get here if we‘re the parent process.
  69. //! waitpid()阻塞等待子进程结束
  70. //! 函数原型:
  71. deadpid = waitpid(kidpid, &kidstatus, 0);
  72. if (deadpid == -1)
  73. {
  74. printf("error to fork a process!");
  75. return 1;
  76. }
  77. else
  78. {
  79. return 0;
  80. }
  81. }
  82. else
  83. {
  84. printf("Authenticate failed\n");
  85. return 1;
  86. }
  87. }

最后,利用gcc编译该文件:gcc  test_exec.c  -o  test_exec;编译完成后为它赋予权限:chmod 777 test_exec;然后设置用户标记位:s, chmod  u+s  test_exec

执行测试:

1. 利用root用户创建一个del_test文件,然后切换到普通用户,测试能否删除;然后用我们的命令模拟root用户看能否删除

2. 利用root用户创建一个del_test的文件,切换到zhangsan用户,利用命令模拟lisi用户,看能够删除

通过以上,我们可以看出,利用该命令我们可以模拟任何用户的身份,相当于任何权限都是由你自己控制,在一定程度上保证了安全性。

总结:

对似懂非懂的知识点一定要明白其原理,不然始终不知道应该如何来做。加油!这段时间的网盘开发没有涉及太多挑战性的东西,期待UDT的研究。

参考:http://blog.csdn.net/houqd2012/article/details/34165381

时间: 2024-10-13 18:39:30

万能脚本助Web执行底层Linux命令的相关文章

【大话QT之十一】题外篇:万能脚本助Web执行底层Linux命令

需求分析: 这里先要说明的是,这一篇不是QT系列的文章,而是关于Web的,之所以要写这篇,是因为以前做Web相关开发的时候,经常涉及到与linux底层命令打交道,比如说创建一个目录,删除一个目录,或者是执行一个自定义的脚本.关于PHP如何调用.执行Linux的底层命令,以前也研究过,基本上实现了自己需要的功能,但是有些地方一直没有弄明白.今天又偶然碰到了,趁着这个机会向大家描述一下一步一步应该如何实现,并最后附上相关C代码. 原理实现: 首先,一般搭建的Web站点都是采用Apache或Nginx

shell,shell脚本结构和执行方法,data命令,shell脚本中的变量

shell是什么shell是一种脚本语言 aming_linux blog.lishiming.net可以使用逻辑判断.循环等语法可以自定义函数shell是系统命令的集合shell脚本可以实现自动化运维,能大大增加我们的运维效率 shell脚本结构和执行方法开头需要加#!/bin/bash以#开头的行作为解释说明脚本的名字以.sh结尾,用于区分这是一个shell脚本执行方法有两种chmod +x 1.sh; ./1.shbash 1.sh查看脚本执行过程 bash -x 1.sh查看脚本是否语法

shell脚本介绍,shell脚本结构和执行,date命令用法,shell脚本中的变量

Shell脚本介绍 shell是一种脚本语言 blog.lishiming.net(阿铭的博客,可以去里面找shell习题)可以使用逻辑判断.循环等语法可以自定义函数,减少重复代码shell是系统命令的集合shell脚本可以实现自动化运维,能大大增加我们的运维效率 Shell脚本结构和执行 开头需要加#!/bin/bash 以#开头的行作为解释说明 脚本的名字以.sh结尾,用于区分这是一个shell脚本写一个简简单的脚本#!/bin/bash#Linletao#2018-5-29echo llt

六十七、shell脚本介绍、shell脚本结构和执行、date命令用法、shell脚本中的变量

一.shell脚本介绍 shell是一种脚本语言  aming_linux  blog.lishiming.net 可以使用逻辑判断.循环等语法 可以自定义函数 定义函数的目的:为了简化,为了减少重复的代码. shell是系统命令的集合 shell脚本可以实现自动化运维,能大大增加我们的运维效率 二.shell脚本结构和执行 脚本示例: #!/bin/bash echo "123" w ls 开头需要加#!/bin/bash,这个脚本在当前机器执行能识别里面的命令,换一台机器也许就不能

68.shell脚本介绍、shell脚本结构和执行、date命令用法、shell脚本中的变量

一.shell是什么 shell是一种脚本语言 aming_linux blog.lishiming.net 可以使用逻辑判断.循环等语法 可以自定义函数 shell是系统命令的集合 shell脚本可以实现自动化运维,能大大增加我们的运维效率 二.shell脚本结构和执行方法 开头需要加#!/bin/bash 以#开头的行作为解释说明 脚本的名字以.sh结尾,用于区分这是一个shell脚本 执行方法有两种 chmod +x 1.sh; ./1.sh bash 1.sh 查看脚本执行过程 bash

shell脚本介绍、shell脚本结构和执行、date命令用法、shell脚本中的变量

shell脚本介绍 shell脚本结构和执行 开头需要加#!/bin/bash 因为有了#!/bin/bash文件头所以需要给01.sh文件执行权限 [[email protected] shell]# chmod a+x 01.sh 以#开头的行作为解释说明 脚本的名字以.sh结尾,用于区分这是一个shell脚本 执行方法有两种chmod +x 1.sh; ./1.shbash 1.sh 查看脚本执行过程 bash -x 1.sh 查看脚本是否语法错误 bash -n 1.sh date命令用

jenkins 执行远程linux命令

在Jenkins中进行构建时,可能需要首先SSH登录到一个远程服务器以执行必要的脚本,然后再执行构建.这时,需要安装SSH Plugin,并进行如下配置. 1.在Jenkins界面,系统管理->管理插件->安装SSH Plugin 说明,SSH Plugin的目的就是支持SSH到远程服务器,然后执行Shell命令. 2.在Jenkins界面,系统管理->Configure(配置)->SSH remote hosts 配置要SSH远程连接的服务器信息,示例如下: Hostname:

一个shell脚本,让你的linux命令行酷炫起来

#!/bin/bash # This program is to modify showed marked## biaoshi.sh 207# by wangxianzheng 2011/12/20 PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/binecho "########execute $

Java程序执行Linux命令(JSP运行其他程序)

java程序中要执行linux命令主要依赖2个类:Process和Runtime 首先看一下Process类: ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获得相关信息.Process 类提供了执行从进程输入.执行输出到进程.等待进程完成. 检查进程的退出状态以及销毁(杀掉)进程的方法. 创建进程的方法可能无法针对某些本机平台上的特定进程很好地工作,比如,本机窗口进程,守护进程,M