国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

node.js實(shí)現(xiàn)web終端操作多用戶

來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 19:55:01
文檔

node.js實(shí)現(xiàn)web終端操作多用戶

node.js實(shí)現(xiàn)web終端操作多用戶:這次給大家?guī)韓ode.js實(shí)現(xiàn)web終端操作多用戶,node.js實(shí)現(xiàn)web終端操作多用戶的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來看一下。terminal(命令行)作為本地IDE普遍擁有的功能,對(duì)項(xiàng)目的git操作以及文件操作有著非常強(qiáng)大的支持。對(duì)于WebIDE,在沒有w
推薦度:
導(dǎo)讀node.js實(shí)現(xiàn)web終端操作多用戶:這次給大家?guī)韓ode.js實(shí)現(xiàn)web終端操作多用戶,node.js實(shí)現(xiàn)web終端操作多用戶的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來看一下。terminal(命令行)作為本地IDE普遍擁有的功能,對(duì)項(xiàng)目的git操作以及文件操作有著非常強(qiáng)大的支持。對(duì)于WebIDE,在沒有w

這次給大家?guī)韓ode.js實(shí)現(xiàn)web終端操作多用戶,node.js實(shí)現(xiàn)web終端操作多用戶的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來看一下。

terminal(命令行)作為本地IDE普遍擁有的功能,對(duì)項(xiàng)目的git操作以及文件操作有著非常強(qiáng)大的支持。對(duì)于WebIDE,在沒有web偽終端的情況下,僅僅提供封裝的命令行接口是完全不能滿足開發(fā)者使用,因此為了更好的用戶體驗(yàn),web偽終端的開發(fā)也就提上日程。

調(diào)研

終端,在我們認(rèn)知范圍內(nèi)略同于命令行工具,通俗點(diǎn)說就是可以執(zhí)行shell的進(jìn)程。每次在命令行中輸入一串命令,敲入回車,終端進(jìn)程都會(huì)fork一個(gè)子進(jìn)程,用來執(zhí)行輸入的命令,終端進(jìn)程通過系統(tǒng)調(diào)用wait4()監(jiān)聽子進(jìn)程退出,同時(shí)通過暴露的stdout輸出子進(jìn)程執(zhí)行信息。

如果在web端實(shí)現(xiàn)一個(gè)類似于本地化的終端功能,需要做的可能會(huì)更多:網(wǎng)絡(luò)時(shí)延及可靠性保證、shell用戶體驗(yàn)盡量接近本地化、web終端UI寬高與輸出信息適配、安全準(zhǔn)入控制與權(quán)限管理等。在具體實(shí)現(xiàn)web終端之前,需要評(píng)估這些功能那些是最核心的,很明確:shell的功能實(shí)現(xiàn)及用戶體驗(yàn)、安全性(web終端是在線上服務(wù)器中提供的一個(gè)功能,因此安全性是必須要保證的)。只有在保證這兩個(gè)功能的前提下,web偽終端才可以正式上線。

下面首先針對(duì)這兩個(gè)功能考慮下技術(shù)實(shí)現(xiàn)(服務(wù)端技術(shù)采用nodejs):

node原生模塊提供了repl模塊,它可以用來實(shí)現(xiàn)交互式輸入并執(zhí)行輸出,同時(shí)提供tab補(bǔ)全功能,自定義輸出樣式等功能,可是它只能執(zhí)行node相關(guān)命令,因此無法達(dá)到我們想要執(zhí)行系統(tǒng)shell的目的 node原生模塊child_porcess,它提供了spawn這種封裝了底層libuv的uv_spawn函數(shù),底層執(zhí)行系統(tǒng)調(diào)用fork和execvp,執(zhí)行shell命令。但是它未提供偽終端的其它特點(diǎn),如tab自動(dòng)補(bǔ)全、方向鍵顯示歷史命令等操作

因此,服務(wù)端采用node的原生模塊是無法實(shí)現(xiàn)一個(gè)偽終端的,需要繼續(xù)探索偽終端的原理和node端的實(shí)現(xiàn)方向。

偽終端

偽終端不是真正的終端,而是內(nèi)核提供的一個(gè)“服務(wù)”。終端服務(wù)通常包括三層:

最頂層提供給字符設(shè)備的輸入輸出接口中間層的線路規(guī)程(line discipline)底層的硬件驅(qū)動(dòng)

其中,最頂層的接口往往通過系統(tǒng)調(diào)用函數(shù)實(shí)現(xiàn),如(read,write);而底層的硬件驅(qū)動(dòng)程序則負(fù)責(zé)偽終端的主從設(shè)備通信,它由內(nèi)核提供;線路規(guī)程看起來則比較抽象,但是實(shí)際上從功能上說它負(fù)責(zé)輸入輸出信息的“加工”,如處理輸入過程中的中斷字符(ctrl + c)以及一些回退字符(backspace 和 delete)等,同時(shí)轉(zhuǎn)換輸出的換行符n為rn等。

一個(gè)偽終端分為兩部分:主設(shè)備和從設(shè)備,他們底層通過實(shí)現(xiàn)默認(rèn)線路規(guī)程的雙向管道連接(硬件驅(qū)動(dòng))。偽終端主設(shè)備的任何輸入都會(huì)反映到從設(shè)備上,反之亦然。從設(shè)備的輸出信息也通過管道發(fā)送給主設(shè)備,這樣可以在偽終端的從設(shè)備中執(zhí)行shell,完成終端的功能。

偽終端的從設(shè)備中,可以真實(shí)的模擬終端的tab補(bǔ)全和其他的shell特殊命令,因此在node原生模塊不能滿足需求的前提下,我們需要把目光放到底層,看看OS提供了什么功能。目前,glibc庫(kù)提供了posix_openpt接口,不過流程有些繁瑣:

使用posix_openpt打開一個(gè)偽終端主設(shè)備 grantpt設(shè)置從設(shè)備的權(quán)限 unlockpt解鎖對(duì)應(yīng)的從設(shè)備獲取從設(shè)備名稱(類似 /dev/pts/123)主(從)設(shè)備讀寫,執(zhí)行操作

因此出現(xiàn)了封裝更好的pty庫(kù),僅僅通過一個(gè)forkpty函數(shù)便可以實(shí)現(xiàn)上述所有功能。通過編寫一個(gè)node的c++擴(kuò)展模塊,搭配pty庫(kù)實(shí)現(xiàn)一個(gè)在偽終端從設(shè)備執(zhí)行命令行的terminal。

關(guān)于偽終端安全性的問題,我們?cè)谖恼碌淖詈笤谶M(jìn)行討論。

偽終端實(shí)現(xiàn)思路

根據(jù)偽終端的主從設(shè)備的特性,我們?cè)谥髟O(shè)備所在的父進(jìn)程中管理偽終端的生命周期及其資源,在從設(shè)備所在的子進(jìn)程中執(zhí)行shell,執(zhí)行過程中的信息及結(jié)果通過雙向管道傳輸給主設(shè)備,由主設(shè)備所在的進(jìn)程向外提供stdout。

在此處借鑒pty.js的實(shí)現(xiàn)思路:

pid_t pid = pty_forkpty(&master, name, NULL, &winp);
 switch (pid) {
 case -1:
 return Nan::ThrowError("forkpty(3) failed.");
 case 0:
 if (strlen(cwd)) chdir(cwd);
 if (uid != -1 && gid != -1) {
 if (setgid(gid) == -1) {
 perror("setgid(2) failed.");
 _exit(1);
 }
 if (setuid(uid) == -1) {
 perror("setuid(2) failed.");
 _exit(1);
 }
 }
 pty_execvpe(argv[0], argv, env);
 perror("execvp(3) failed.");
 _exit(1);
 default:
 if (pty_nonblock(master) == -1) {
 return Nan::ThrowError("Could not set master fd to nonblocking.");
 }
 Local<Object> obj = Nan::New<Object>();
 Nan::Set(obj,
 Nan::New<String>("fd").ToLocalChecked(),
 Nan::New<Number>(master));
 Nan::Set(obj,
 Nan::New<String>("pid").ToLocalChecked(),
 Nan::New<Number>(pid));
 Nan::Set(obj,
 Nan::New<String>("pty").ToLocalChecked(),
 Nan::New<String>(name).ToLocalChecked());
 pty_baton *baton = new pty_baton();
 baton->exit_code = 0;
 baton->signal_code = 0;
 baton->cb.Reset(Local<Function>::Cast(info[8]));
 baton->pid = pid;
 baton->async.data = baton;
 uv_async_init(uv_default_loop(), &baton->async, pty_after_waitpid);
 uv_thread_create(&baton->tid, pty_waitpid, static_cast<void*>(baton));
 return info.GetReturnValue().Set(obj);
 }

首先通過pty_forkpty(forkpty的posix實(shí)現(xiàn),兼容 sunOS和 unix等系統(tǒng))創(chuàng)建主從設(shè)備,然后在子進(jìn)程中設(shè)置權(quán)限之后(setuid、setgid),執(zhí)行系統(tǒng)調(diào)用pty_execvpe(execvpe的封裝),此后主設(shè)備的輸入信息都會(huì)在此得到執(zhí)行(子進(jìn)程執(zhí)行的文件為sh,會(huì)偵聽stdin);

父進(jìn)程則向node層暴露相關(guān)對(duì)象,如主設(shè)備的fd(通過該fd可以創(chuàng)建net.Socket對(duì)象進(jìn)行數(shù)據(jù)雙向傳輸),同時(shí)注冊(cè)libuv的消息隊(duì)列&baton->async,當(dāng)子進(jìn)程退出時(shí)觸發(fā)&baton->async消息,執(zhí)行pty_after_waitpid函數(shù);

最后父進(jìn)程通過調(diào)用uv_thread_create創(chuàng)建一個(gè)子進(jìn)程,用于偵聽上一個(gè)子進(jìn)程的退出消息(通過執(zhí)行系統(tǒng)調(diào)用wait4,阻塞偵聽特定pid的進(jìn)程,退出信息存放在第三個(gè)參數(shù)中),pty_waitpid函數(shù)封裝了wait4函數(shù),同時(shí)在函數(shù)末尾執(zhí)行uv_async_send(&baton->async)觸發(fā)消息。

在底層實(shí)現(xiàn)pty模型后,在node層需要做一些stdio的操作。由于偽終端主設(shè)備是在父進(jìn)程中執(zhí)行系統(tǒng)調(diào)用的創(chuàng)建的,而且主設(shè)備的文件描述符通過fd暴露給node層,那么偽終端的輸入輸出也就通過讀寫根據(jù)fd創(chuàng)建對(duì)應(yīng)的文件類型如PIPE、FILE來完成。其實(shí),在OS層面就是把偽終端主設(shè)備看為一個(gè)PIPE,雙向通信。在node層通過net.Socket(fd)創(chuàng)建一個(gè)套接字實(shí)現(xiàn)數(shù)據(jù)流的雙向IO,偽終端的從設(shè)備也有著主設(shè)備相同的輸入,從而在子進(jìn)程中執(zhí)行對(duì)應(yīng)的命令,子進(jìn)程的輸出也會(huì)通PIPE反應(yīng)在主設(shè)備中,進(jìn)而觸發(fā)node層Socket對(duì)象的data事件。

此處關(guān)于父進(jìn)程、主設(shè)備、子進(jìn)程、從設(shè)備的輸入輸出描述有些讓人迷惑,在此解釋。父進(jìn)程與主設(shè)備的關(guān)系是:父進(jìn)程通過系統(tǒng)調(diào)用創(chuàng)建主設(shè)備(可看做是一個(gè)PIPE),并獲取主設(shè)備的fd。父進(jìn)程通過創(chuàng)建該fd的connect socket實(shí)現(xiàn)向子進(jìn)程(從設(shè)備)的輸入輸出。 而子進(jìn)程通過forkpty 創(chuàng)建后執(zhí)行l(wèi)ogin_tty操作,重置了子進(jìn)程的stdin、stderr和stderr,全部復(fù)制為從設(shè)備的fd(PIPE的另一端)。因此子進(jìn)程輸入輸出都是與從設(shè)備的fd相關(guān)聯(lián)的,子進(jìn)程輸出數(shù)據(jù)走的是PIPE,并從PIPE中讀入父進(jìn)程的命令。詳情請(qǐng)看參考文獻(xiàn)之forkpty實(shí)現(xiàn)

另外,pty庫(kù)提供了偽終端的大小設(shè)置,因此我們通過參數(shù)可以調(diào)整偽終端輸出信息的布局信息,因此這也提供了在web端調(diào)整命令行寬高的功能,只需在pty層設(shè)置偽終端窗口大小即可,該窗口是以字符為單位。

web終端安全性保證

基于glibc提供的pty庫(kù)實(shí)現(xiàn)偽終端后臺(tái),是沒有任何安全性保證的。我們想通過web終端直接操作服務(wù)端的某個(gè)目錄,但是通過偽終端后臺(tái)可以直接獲取root權(quán)限,這對(duì)服務(wù)而言是不可容忍的,因?yàn)樗苯佑绊懼?wù)器的安全,所有需要實(shí)現(xiàn)一個(gè):可多用戶同時(shí)在線、可配置每個(gè)用戶訪問權(quán)限、可訪問特定目錄的、可選擇配置bash命令、用戶間相互隔離、用戶無感知當(dāng)前環(huán)境且環(huán)境簡(jiǎn)單易部署的“系統(tǒng)”。

最為適合的技術(shù)選型是docker,作為一種內(nèi)核層面的隔離,它可以充分利用硬件資源,且十分方便映射宿主機(jī)的相關(guān)文件。但是docker并不是萬能的,如果程序運(yùn)行在docker容器中,那么為每個(gè)用戶再分配一個(gè)容器就會(huì)變得復(fù)雜得多,而且不受運(yùn)維人員掌控,這就是所謂的DooD(docker out of docker)-- 通過volume “/usr/local/bin/docker”等二進(jìn)制文件,使用宿主機(jī)的docker命令,開啟兄弟鏡像運(yùn)行構(gòu)建服務(wù)。而采用業(yè)界經(jīng)常討論的docker-in-docker模式會(huì)存在諸多缺點(diǎn),特別是文件系統(tǒng)層面的,這在參考文獻(xiàn)中可以找到。因此,docker技術(shù)并不適合已經(jīng)運(yùn)行在容器中的服務(wù)解決用戶訪問安全問題。

接下來需要考慮單機(jī)上的解決方案。目前筆者只想到兩種方案:

命令A(yù)CL,通過命令白名單的方式實(shí)現(xiàn) restricted bash chroot,針對(duì)每個(gè)用戶創(chuàng)建一個(gè)系統(tǒng)用戶,監(jiān)禁用戶訪問范圍

首先,命令白名單的方式是最應(yīng)該排除的,首先無法保證不同release的linux的bash是相同的;其次無法有效窮舉所有的命令;最后由于偽終端提供的tab命令補(bǔ)全功能以及特殊字符如delete的存在,無法有效匹配當(dāng)前輸入的命令。因此白名單方式漏洞太多,放棄。

restricted bash,通過/bin/bash -r觸發(fā),可以限制使用者顯式“cd directory”,但有這諸多缺點(diǎn):

不足以允許執(zhí)行完全不受信任的軟件。當(dāng)一個(gè)被發(fā)現(xiàn)是shell腳本的命令被執(zhí)行時(shí),rbash會(huì)關(guān)閉在shell中生成的任何限制來執(zhí)行腳本。當(dāng)用戶從rbash運(yùn)行bash或dash,那么他們獲得了無限制的shell。有很多方法來打破受限制的bash shell,這是不容易預(yù)測(cè)的。

最后,貌似只有一個(gè)解決方案了,即chroot。chroot修改了用戶的根目錄,在制定的根目錄下運(yùn)行指令。在指定根目錄下無法跳出該目錄,因此無法訪問原系統(tǒng)的所有目錄;同時(shí)chroot會(huì)創(chuàng)建一個(gè)與原系統(tǒng)隔離的系統(tǒng)目錄結(jié)構(gòu),因此原系統(tǒng)的各種命令無法在“新系統(tǒng)”中使用,因?yàn)樗侨碌摹⒖盏模蛔詈螅鄠€(gè)用戶使用時(shí)他們是隔離的、透明的,完全滿足我們的需求。

因此,我們最終選擇chroot作為web終端的安全性解決方案。但是,使用chroot需要做非常多的額外處理,不僅包括新用戶的創(chuàng)建,還包括命令的初始化。上文也提到“新系統(tǒng)”是空的,所有可執(zhí)行二進(jìn)制文件都沒有,如“l(fā)s,pmd”等,因此初始化“新系統(tǒng)”是必須的。可是許多二進(jìn)制文件不僅僅靜態(tài)鏈接了許多庫(kù),還在運(yùn)行時(shí)依賴動(dòng)態(tài)鏈接庫(kù)(dll),為此還需要找到每個(gè)命令依賴的諸多dll,異常繁瑣。為了幫助使用者從這種無趣的過程中解脫出來,jailkit應(yīng)運(yùn)而生。

jailkit,真好用

jailkit,顧名思義用來監(jiān)禁用戶。jailkit內(nèi)部使用chroot實(shí)現(xiàn)創(chuàng)建用戶根目錄,同時(shí)提供了一系列指令來初始化、拷貝二進(jìn)制文件及其所有的dll,而這些功能都可以通過配置文件進(jìn)行操作。因此,在實(shí)際開發(fā)中采用jailkit搭配初始化shell腳本來實(shí)現(xiàn)文件系統(tǒng)隔離。

此處的初始化shell指的是預(yù)處理腳本,由于chroot需要針對(duì)每個(gè)用戶設(shè)置根目錄,因此在shell中為每個(gè)開通命令行權(quán)限的使用者創(chuàng)建對(duì)應(yīng)的user,并通過jailkit配置文件拷貝基本的二進(jìn)制文件及其dll,如基本的shell指令、git、vim、ruby等;最后再針對(duì)某些命令做額外的處理,以及權(quán)限重置。

在處理“新系統(tǒng)”與原系統(tǒng)的文件映射過程中,還是需要一些技巧。筆者曾經(jīng)將chroot設(shè)定的用戶根目錄之外的其他目錄通過軟鏈接的形式建立映射,可是在jail監(jiān)獄中訪問軟鏈接時(shí)仍會(huì)報(bào)錯(cuò),找不到該文件,這還是由于chroot的特性導(dǎo)致的,沒有權(quán)限訪問根目錄之外的文件系統(tǒng);如果通過硬鏈接建立映射,則針對(duì)chroot設(shè)定的用戶根目錄中的硬鏈接文件做修改是可以的,但是涉及到刪除、創(chuàng)建等操作是無法正確映射到原系統(tǒng)的目錄的,而且硬鏈接無法連接目錄,因此硬鏈接不滿足需求;最后通過mount --bind實(shí)現(xiàn),如 mount --bind /home/ttt/abc /usr/local/abc它通過屏蔽被掛載的目錄(/usr/local/abc)的目錄信息(block),并在內(nèi)存中維護(hù)被掛載目錄與掛載目錄的映射關(guān)系,對(duì)/usr/local/abc的訪問都會(huì)通過傳內(nèi)存的映射表查詢/home/ttt/abc的block,然后進(jìn)行操作,實(shí)現(xiàn)目錄的映射。

最后,初始化“新系統(tǒng)”完畢后,就需要通過偽終端執(zhí)行jail相關(guān)命令:

sudo jk_chrootlaunch -j /usr/local/jailuser/${creater} -u ${creater} -x /bin/bashr

開啟bash程序之后便通過PIPE與主設(shè)備接收到的web終端輸入(通過websocket)進(jìn)行通信即可。

相信看了本文案例你已經(jīng)掌握了方法,更多精彩請(qǐng)關(guān)注Gxl網(wǎng)其它相關(guān)文章!

推薦閱讀:

在angularjs中怎樣實(shí)現(xiàn)echart圖表

js怎么實(shí)現(xiàn)隔行變色

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

node.js實(shí)現(xiàn)web終端操作多用戶

node.js實(shí)現(xiàn)web終端操作多用戶:這次給大家?guī)韓ode.js實(shí)現(xiàn)web終端操作多用戶,node.js實(shí)現(xiàn)web終端操作多用戶的注意事項(xiàng)有哪些,下面就是實(shí)戰(zhàn)案例,一起來看一下。terminal(命令行)作為本地IDE普遍擁有的功能,對(duì)項(xiàng)目的git操作以及文件操作有著非常強(qiáng)大的支持。對(duì)于WebIDE,在沒有w
推薦度:
標(biāo)簽: 用戶 多用戶 web
  • 熱門焦點(diǎn)

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 久久亚洲伊人成综合人影院 | 欧美激情伦妇在线观看 | 欧美日韩国产精品 | 国产手机在线αⅴ片无码观看 | 欧美综合自拍亚洲综合百度 | 亚洲 欧美 视频 | 国产区在线看 | 日本精品久久久一区二区三区 | 欧美日韩综合精品一区二区三区 | 国产成人麻豆精品video | 干比网| 国产精品1000部在线观看 | 在线国产视频 | 欧美日韩国产在线观看 | 日韩欧美91 | 色综合欧美综合天天综合 | 精品久久成人 | 国产一级久久久久久毛片 | 91精品久久久久久久久久 | 日本三级韩国三级韩级在线观看 | 性xxxxfreexxxxx国产| 欧美日韩精品一区二区三区视频播放 | 99久久精品国产国产毛片 | 国产伦精品一区二区三区视频小说 | 欧美日韩国产精品综合 | 日韩欧美综合视频 | 国产免费精彩视频 | 精品亚洲性xxx久久久 | 亚洲综合婷婷 | 国产视频欧美 | 中文国产成人精品久久一 | 亚洲欧美日韩色 | 国产午夜视频在线 | 国产短视频精品一区二区三区 | 国产一区二区在线观看视频 | 91精品国产亚一区二区三区 | 全部费免一级毛片不收费 | 91 久久| 欧美中文日韩 | 精品视频免费看 | 欧美性猛交一区二区三区精品 |