需求分析:
这里先要说明的是,这一篇不是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就可以将进程模拟为任何用户的身份了。
实现代码:
最后,利用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