明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

CGI教學(xué):CGI安全問題(3)

[摘要]2.4 拒絕不合要求的表單數(shù)據(jù) CGI腳本可以有幾種方式拒絕接收提交給它的非預(yù)期的輸入。編寫CGI時應(yīng)該使用其中一些技巧或所有這些技巧。 首先,CGI 腳本應(yīng)設(shè)置接收多少數(shù)據(jù)的限制,不僅限制整個提交,也限制提交中的每個NAME/VALUE對。例如,CGI腳本讀取POST METHOD,檢查CONT...
2.4 拒絕不合要求的表單數(shù)據(jù)

CGI腳本可以有幾種方式拒絕接收提交給它的非預(yù)期的輸入。編寫CGI時應(yīng)該使用其中一些技巧或所有這些技巧。

首先,CGI 腳本應(yīng)設(shè)置接收多少數(shù)據(jù)的限制,不僅限制整個提交,也限制提交中的每個NAME/VALUE對。例如,CGI腳本讀取POST METHOD,檢查CONTENT-LENGTH環(huán)境變量的大小來確定某輸入是不是合理的預(yù)期輸入。如果CGI 腳本設(shè)計接收的唯一數(shù)據(jù)是某人的姓名,那么如果CONTENT-LENGTH大于100字節(jié),就應(yīng)該有理由返回一個錯誤。沒有哪個合理的姓有那么長,通過設(shè)置限制,就能使腳本不再盲目地讀取發(fā)送給它的內(nèi)容。

注意

令人高興的是,不必?fù)?dān)心去限制通過POST方法提交的數(shù)據(jù)。GET是自限制的并且不會向腳本發(fā)送多于1KB的數(shù)據(jù)。服務(wù)器自動限制放人QUERY-STRING環(huán)境變量中的數(shù)據(jù)的大小,而這正是GET發(fā)送給CGI程序的信息。

當(dāng)然,"黑客"們可以很容易地將表單由GET改為PUT從而繞過這種內(nèi)置的限制。至少,程序應(yīng)該檢查一下數(shù)據(jù)是否是用預(yù)期的方法提交的;最好是能正確且安全地處理兩種方法。

下一步,應(yīng)保證腳本知道在接收到不能識別的數(shù)據(jù)時該怎么辦,例如,如果某表單要求用戶選擇兩個單選按鈕之一,腳本就不應(yīng)該假設(shè)因為一個按鈕未被選擇,另一個就一定被選擇了。下面的Perl代碼就犯了這樣的錯誤:

if ($form_Data{"radio_choice"} eq "button_one"){
# Button One has been clicked }
else {
# Button Two has been clicked }

這段代碼假定因為表單僅提供了兩個選項,而第一項未被選中,那么第二項就肯定被選中了。這不一定是真的。盡管前面的例子沒有什么害處,但在某些情況下這樣的假設(shè)可能很危險。

CGI腳本應(yīng)該能預(yù)期這種情形而相應(yīng)地進行處理。例如,如果出現(xiàn)一些非預(yù)期的或"不可能"的情形,可以打印一個錯誤,如下所述:

If ($form_Data{"radio_choice"} eq "button_one") {
#Button One seleted }
elsif ($form_Data{"radio_choice} eq "button_two") {
#Button Two Selected }
else {
#Error }

通過加入第二個if語句--顯式檢查"radio_choice"實際上是"button_two"--這樣腳本更安全了;它不再做假設(shè)了。

當(dāng)然,錯誤不一定是期望腳本在這些情形下生成的。有些腳本過于小心,驗證每個字段,即使是最輕微的非預(yù)期數(shù)據(jù)都生成錯誤信息,這樣往往很掃用戶的興。讓CGI 腳本識別非預(yù)期數(shù)據(jù)然后扔掉它,并且自動選擇一個缺省值也可以。

另一方面,腳本還可幫助用戶糾正錯誤而不是簡單地發(fā)一條錯誤消息或設(shè)置一個缺省值。如果表單要求用戶輸入機密文字,腳本應(yīng)能在進行比較之前自動跳過輸入中的空白字符。下面即是一個完成此功能的Perl程序片段。

$user_input =~ s/\s//;
#Remove white space by replacing it with an empty string
if ($user_input eq $secret_Word) {
#Match! }

最后,可以更進一,讓CGI腳本能處理盡可能多的不同的輸入表單。盡管不可能預(yù)期到可能發(fā)送給CGI程序的所有內(nèi)容,但對某個特定方面一般經(jīng)常有幾種常用的方式,因而可以逐個檢查。

例如,僅僅因為所寫的表單使用POST方法向CGI腳本提交數(shù)據(jù),并不意味著數(shù)據(jù)必須按那種方法進來。應(yīng)該檢查REQUEET_METHOD環(huán)境變量來確定是使用了GET還是POST方法并相應(yīng)地讀取數(shù)據(jù),而不是假定數(shù)據(jù)都是來自預(yù)期的標(biāo)準(zhǔn)輸入(stdin)。一個真正編寫成功的CGI腳本能接收無論使用什么方法提交的數(shù)據(jù)并在處理過程中很安全。以下程序清單即是用Perl編寫的一個例子。

程序清單 CGI_READ.PL 一個充滿活力的讀取格式輸入的程序

#Takes the maximum length allowed as a parameter
#Returns 1 and the raw form data,or "0" and the error text
sub cgi_Read
{
local($input_Max)=1024 unless $input_Max=$_[0];
local($input_Method)=$ENV{'REOUEST_METHOO');
#Check for each possible REQUEST_METHODS
if ($input_Method eq "GET") {
#"GET"
local($input_Size)=length($ENV{'QUERY_STRING'});
#Check the size of the input
if($input_Size>$input_Max) {
return(0,"input too big"); }
#Read the input from QUERY_STRING
return(1,$ENV{'QUERY_TRING'}); }
elsif ($input_Method eq "POST") {
#"POST"
local($input_Size)=$ENV{'CONTENT_LENGTH'};
local($input_Data);
#Check the size of the input
if ($input_Size>$input_Max) {
return(0,"Input too big"); }
#Read the input from stdin
unless (read(STDIN,$input_Data,$input_Size)) {
return(0,"Could not read STDIN"); }
return(1,$Input_Data);
}
#Unrecognized METHOD
return (0,"METHOD not GET POST");
}

 總而言之,腳本應(yīng)該不對接收的表單數(shù)據(jù)進行假設(shè),應(yīng)盡可能預(yù)計意料之外的情形并正確地處理不正確的或錯誤的輸入數(shù)據(jù)。在使用數(shù)據(jù)之前應(yīng)按盡可能多的方式測試它;拒絕不合理的輸入并打印一條錯誤消息;如果某項出錯或漏了應(yīng)自動選擇一個缺省值;甚至可以試圖對輸入進行編碼以成為程序的合理的輸入。選擇哪種方式依賴于自己想花費多少時間和精力,不過記住永遠也不要盲目接收傳給CGI腳來的所有信息。