【夸QT十一】外来物品:通用脚本帮助Web运行基础Linux命令
需求分析:
??????? 需要注意的是在這里第一次,這個人是不是QT系列文章,它是關于Web的,之所以寫這篇文章。這是因為礙著Web相關開發時間,而且往往涉及linux與底層指令處理。例如,創建一個文件夾,刪除一個文件夾,或者是運行一個自己定義的腳本。關于PHP怎樣調用、運行Linux的底層命令。曾經也研究過,基本上實現了自己須要的功能,可是有些地方一直沒有弄明確。今天又偶然碰到了,趁著這個機會向大家描寫敘述一下一步一步應該怎樣實現,并最后附上相關C代碼。
原理實現:
??????? 首先,一般搭建的Web網站都是採用Apache或Nginx。因此當使用php運行linux的命令的時候。在linux端體現出的時Apache或Nginx用戶的身份來運行的。通常情況下基于安全考慮。Apache或Nginx在linux端的默認用戶是不具有非常高的權限的,比方刪除、創建等。因此我們必須通過一種方式。為其賦予一定的權限。
在我曾經寫過的文章中,我採用了一種方法,即將Apache或Nginx的默認用戶改動了,給那個用戶賦予了非常高的權限。盡管達到了我的目的,可是恰恰造成了最大的隱患,即:webserver默認用戶權限設置過大,非常easy受到來自外界的攻擊,甚至不用外界。我自己在php端運行一個命令能將我整個網站刪除掉。而在linux端對此基本沒有不論什么防御能力。基于此。我們提出一種方式。在linux端不改動webserver默認用戶的權限,而是當運行命令時由我們來自己控制這條命令應當具有何種用戶的運行權限。或者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就能夠將進程模擬為不論什么用戶的身份了。
實現代碼:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <pwd.h> #include <math.h> #include <time.h>//Usage: exefile command work_directory username password int main(int argc, char *argv[]) {char *username = NULL;char *password = NULL;char *command = NULL;char *workdir = NULL;struct passwd *stpasswd = NULL;if(argc == 5) {command = argv[1];workdir = argv[2]; //work directoryusername = argv[3];password = argv[4]; }else{return 1;}//printf("username = %s\n",username);//printf("password = %s\n",password);//printf("workdir = %s\n",workdir);//printf("command = %s\n",command);int result = 0;//auth(username,password); //Ensure the user is a legel user in the systemif(result == 0) //auth successfully{ int kidstatus, deadpid;//! fork()克隆出一個全然同樣的進程出來;它會復制當前進程的全部變量,就好像一個進程克隆出來還有一個一樣//! fork()函數的返回值有三種情況:=0代表克隆出來的那個進程 >0代表“父”進程 <0 運行出錯//! 這樣的情況一般就是fork出來新的進程。【可選:進行身份切換】,然后利用它來運行execlp(),運行相關的命令pid_t kidpid = fork();if (kidpid == -1) {printf("fork error");return 1;}if (kidpid == 0) { //! getpwnam():獲取用戶登錄相關的信息//! 頭文件:#include <pwd.h> #include <sys/types.h>stpasswd = getpwnam(username); //! setgid():設置實際用戶組ID和有效用戶組ID//! setuid():設置實際用戶ID和有效用戶ID//! chdir() : 改動當前文件夾//! 注意:假設是一個非特權用戶,則它運行setgid和setuid僅僅能設置為自己的gid和uid。而不能設置其他不論什么數值//! 假設是一個特權用戶(即:擁有root權限)。則能夠利用setgid和setuid設置為隨意數值,這也就是為什么終于//! 編譯出來的文件要通過:chmod u+s 設置特權位setgid( (int)(stpasswd->pw_gid)); //Set current usergroupsetuid( (int)(stpasswd->pw_uid)); //Set current userchdir(workdir); //change work directory//! int execlp(const char *file, const char *arg, ..., (char *)0);//! execlp()會從PATH環境變量所指的文件夾中查找符合參數file的文件名稱,找到后便運行該文件,然后//! 將第二個參數以后的參數當作該文件的argv[0], argv[1] ...,最后一個參數必須用空指針(NULL)結束//! 以下的命令就是:/bin/bash -c command運行int rv = execlp("/bin/bash", "/bin/bash", "-c", command, NULL); fflush(stdout); return rv; }//! we only get here if we're the parent process.//! waitpid()堵塞等待子進程結束//! 函數原型:deadpid = waitpid(kidpid, &kidstatus, 0);if (deadpid == -1) {printf("error to fork a process!");return 1;}else{return 0;}}else{printf("Authenticate failed\n");return 1; }}最后。利用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科研。
版權聲明:本文博主原創文章,博客,未經同意不得轉載。
轉載于:https://www.cnblogs.com/blfshiye/p/4851376.html
總結
以上是生活随笔為你收集整理的【夸QT十一】外来物品:通用脚本帮助Web运行基础Linux命令的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实现百度地图导航Demo的语音播报功能
- 下一篇: leetcode之Divide Two