當前位置:成語大全網 - 漢語詞典 - php代碼註釋安全嗎?

php代碼註釋安全嗎?

Php安全值過濾用戶輸入的人體參數。

規則1:永遠不要相信外部數據或輸入。

關於Web應用程序的安全性,您必須認識到的第壹件事是,您不應該信任外部數據。外部數據包括程序員在PHP代碼中沒有直接輸入的任何數據。在采取措施確保安全性之前,來自任何其他來源(如GET變量、表單POST、數據庫、配置文件、會話變量或cookie)的任何數據都是不可信的。

例如,以下數據元素可以被認為是安全的,因為它們是在PHP中設置的。

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ myUsername = ' tmyer

$arrayUsers = array('tmyer ',' tom ',' tommy ');定義(“問候”,“妳好”。$ my username);?& gt

但是,下面的數據元素都有缺陷。

清單2。不安全和有缺陷的代碼

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ my username = $ _ POST[' username '];//汙點!

$arrayUsers = array($myUsername,' tom ',' tommy ');//汙點!

定義(“問候”,“妳好”。$ my username);//汙點!

& gt

為什麽第壹個變量$myUsername有缺陷?因為它直接來自於表單帖子。用戶可以在此輸入字段中輸入任何字符串,包括清除文件或運行以前上傳的文件的惡意命令。您可能會問,“難道不能通過使用只接受字母A-Z的客戶端(javascr: pt)表單驗證腳本來避免這種危險嗎?”是的,這總是壹個有益的步驟,但是正如您稍後將看到的,任何人都可以將任何表單下載到他們自己的機器上,修改它,然後根據需要重新提交。

解決方案很簡單:您必須在$_POST['username']上運行清理代碼。如果不這樣做,您可能會在其他任何時候使用$myUsername時汙染這些對象,比如在數組或常量中。

清理用戶輸入的壹個簡單方法是使用正則表達式來處理它。在本例中,只需要字母。將字符串限制在壹定數量的字符內,或者要求所有字母都是小寫也是壹個好主意。

清單3。確保用戶輸入的安全

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ my username = clean input($ _ POST[' username ']);//幹凈!

$arrayUsers = array($myUsername,' tom ',' tommy ');//幹凈!

定義(“問候”,“妳好”。$ my username);//幹凈!

函數cleanInput($input){

$ clean = strtolower($ input);

$clean = preg_replace("/[^a-z]/“,”,$ clean);$clean = substr($clean,0,12);

返回$ clean

}

& gt

規則2:禁用使安全性難以實現的PHP設置。妳已經知道妳不能相信用戶輸入,妳也應該知道妳不應該相信PHP在機器上的配置方式。例如,確保register_globals被禁用。如果啟用了register_globals,您可能會做壹些粗心的事情,比如用$variable替換GET或POST字符串。通過禁用此設置,PHP會強制您在正確的名稱空間中引用正確的變量。要使用POST表單中的變量,您應該引用$_POST['variable']。這樣,這個特定的變量就不會被誤解為cookie、會話或GET變量。

規則三:如果妳不能理解它,妳就不能保護它

壹些開發人員使用奇怪的語法,或者緊密地組織語句以形成簡短但不明確的代碼。這種方法可能是高效的,但是如果妳不理解代碼在做什麽,妳就不能決定如何保護它。

比如妳喜歡下面兩段代碼中的哪壹段?

清單4。使代碼易於保護

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

//模糊代碼

$ input =(isset($ _ POST[' username '])?$ _ POST[' username ']:);//未混淆的代碼

$ input = ";

if(isset($ _ POST[' username ']){

$ input = $ _ POST[' username '];

}否則{

$ input = ";

}

& gt

在第二個清晰的代碼段中,很容易看出$input是有缺陷的,需要清理後才能安全處理。

規則四:“縱深防禦”是新的法寶。

本教程將使用示例來說明如何保護在線表單,同時在處理表單的PHP代碼中采取必要的措施。類似地,即使您使用PHP regex來確保GET變量完全是數字,您仍然可以采取措施來確保SQL查詢使用轉義的用戶輸入。

深度防禦不僅是壹個好主意,它可以確保妳不會陷入嚴重的麻煩。

既然已經討論了基本規則,讓我們來研究第壹個威脅:SQL註入攻擊。

防止SQL註入攻擊

在SQL註入攻擊中,用戶通過操縱表單或獲取查詢字符串向數據庫查詢添加信息。例如,假設您有壹個簡單的登錄數據庫。該數據庫中的每個記錄都有壹個用戶名字段和壹個密碼字段。構建壹個登錄表單,以便用戶可以登錄。

清單5。簡單登錄表單

復制代碼代碼如下:

& lthtml & gt

& lthead & gt

& lttitle & gt登錄& lt/title & gt;

& lt/head & gt;

& ltbody & gt

& ltform action = " verify . PHP " method = " post " & gt;

& ltp & gt& lt='user '的標簽& gt用戶名& lt/label & gt;

& lt輸入類型= ' text ' name = ' user ' id = ' user '/& gt;

& lt/p & gt;

& ltp & gt& lt='pw ' >的標簽;密碼& lt/label & gt;

& lt輸入類型= '密碼'名稱= '密碼' id= '密碼'/& gt;

& lt/p & gt;

& ltp & gt& lt輸入類型= '提交'值= '登錄'/& gt;& lt/p & gt;

& lt/form & gt;

& lt/body & gt;

& lt/html & gt;

該表單接受用戶輸入的用戶名和密碼,並將用戶輸入提交到壹個名為verify.php的文件中。在這個文件中,PHP如下處理來自登錄表單的數據:

清單6。不安全的PHP表單處理代碼

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ okay = 0;

$ username = $ _ POST[' user '];

$ pw = $ _ POST[' pw '];

$ SQL = " select count(*)as CTR from username = ' "$username。而密碼= '”。$pw。”極限1 ”;$ result = MySQL _ query($ SQL);

while($ data = MySQL _ fetch _ object($ result)){ if($ data-& gt;ctr == 1){

//他們沒事進入應用!

$ okay = 1;

}

}

如果($好的){

$ _ SESSION[' log in okay ']= true;

header(" index . PHP ");

}否則{

header(" log in . PHP ");

}

& gt

這段代碼看起來不錯,不是嗎?全世界數百個(甚至數千個)PHP/MySQL站點都在使用這段代碼。錯在哪裏?好吧,記住“妳不能相信用戶輸入”。沒有來自用戶的信息在這裏被轉義,這使得應用程序易受攻擊。具體來說,任何類型的SQL註入攻擊都可能發生。

例如,如果用戶輸入foo作為用戶名,輸入' or '1'='1作為密碼,下面的字符串實際上會被傳遞給PHP,然後查詢會被傳遞給MySQL:

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ SQL = " select count(*)as CTR from users where username = ' foo ' and password = " or ' 1 ' = ' 1 ' limit 1 ";?& gt

這個查詢總是返回1的計數值,所以PHP將允許訪問。通過在密碼字符串的末尾註入壹些惡意的SQL,黑客可以偽裝成合法用戶。

解決這個問題的方法是使用PHP內置的mysql_real_escape_string()函數作為任何用戶輸入的包裝器。該函數對字符串中的字符進行轉義,使得字符串無法傳遞撇號等特殊字符,並允許MySQL根據特殊字符進行操作。清單7顯示了帶有轉義處理的代碼。

清單7。安全PHP表單處理代碼

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ okay = 0;

$ username = $ _ POST[' user '];

$ pw = $ _ POST[' pw '];

$ SQL = " select count(*)as CTR from username = ' "MySQL _ real _ escape _ string($ username)。”而密碼= '”。mysql_real_escape_string($pw)。”極限1 ”;$ result = MySQL _ query($ SQL);

while($ data = MySQL _ fetch _ object($ result)){ if($ data-& gt;ctr == 1){

//他們沒事進入應用!

$ okay = 1;

}

}

如果($好的){

$ _ SESSION[' log in okay ']= true;

header(" index . PHP ");

}否則{

header(" log in . PHP ");

}

& gt

使用mysql_real_escape_string()作為用戶輸入的包裝器可以避免用戶輸入中的任何惡意sql註入。如果用戶試圖通過SQL註入傳遞格式錯誤的密碼,以下查詢將被傳遞到數據庫:

select count(*)as CTR from users where username = ' foo ' and password = ' \ ' or \ ' 1 \ ' = \ ' 1 ' limit 1 "數據庫中沒有與此類密碼匹配的內容。只需壹個簡單的步驟就可以堵住Web應用程序中的壹個大漏洞。這裏的教訓是,用戶輸入的SQL查詢應該總是被轉義。

然而,仍有幾個安全漏洞需要堵塞。下壹項是操作GET變量。

防止用戶操縱GET變量。

在上壹節中,用戶被禁止使用格式錯誤的密碼登錄。如果妳很聰明,妳應該應用妳所學的方法來確保所有用戶輸入的SQL語句都被轉義。

但是,用戶現在已經安全登錄。僅僅因為壹個用戶有壹個有效的密碼並不意味著他會遵守規則——他有很多機會做出傷害。例如,應用程序可能允許用戶查看特殊內容。所有線索都指向template.php?Pid=33還是template.php?Pid=321。URL中問號後面的部分稱為查詢字符串。因為查詢字符串直接放在URL中,所以也稱為GET查詢字符串。

在PHP中,如果register_globals被禁用,可以用$_GET['pid']訪問這個字符串。在template.php頁面中,您可能會做類似於清單8的事情。

清單8。template.php樣本

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ PID = $ _ GET[' PID '];

//我們創建壹個虛構類Page$obj = new Page的對象;

$ content = $ obj-& gt;fetch page($ PID);

//現在我們有了壹堆顯示頁面的PHP?& gt

這裏有什麽問題嗎?首先,隱式地認為從瀏覽器獲取變量pid是安全的。會發生什麽?大多數用戶不夠聰明,無法構造語義攻擊。但是,如果他們在瀏覽器的URL位置域中註意到pid=33,他們就可能開始搗亂。如果他們輸入另壹個數字,可能還可以;但是,如果輸入其他內容,比如SQL命令或文件名(比如/etc/passwd),或者玩其他惡作劇,比如輸入3000個字符的數值,會發生什麽情況呢?

在這種情況下,記住基本規則,不要相信用戶輸入。應用開發者知道template.php接受的個人標識符(PID)應該是壹個數字,所以可以用PHP的is_numeric()函數來保證不接受非數字的PID,如下圖:

清單9。使用is_numeric()來限制GET變量的復制。代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ PID = $ _ GET[' PID '];

if (is_numeric($pid)){

//我們創建壹個虛構類Page$obj = new Page的對象;

$ content = $ obj-& gt;fetch page($ PID);

//現在我們有了壹堆PHP來顯示頁面}else{

//沒有通過is_numeric()測試,做點別的!

}

& gt

這種方法看起來很有效,但是下面的輸入很容易通過is_numeric()的檢查:

100(有效)

100.1(應該沒有小數位)

+0123.45e6(科學的計數方法——不好)

0xff33669f(十六進制-危險!危險!)那麽,壹個有安全意識的PHP開發者應該怎麽做呢?多年的經驗表明,最佳實踐是使用正則表達式來確保整個GET變量由數字組成,如下所示:

清單10。使用正則表達式限制GET變量

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ PID = $ _ GET[' PID '];

if(strlen $ PID)){

如果(!ereg("^[0-9]+$",$pid)){

//做壹些適當的事情,比如將他們註銷或發送回主頁}

}否則{

//清空$pid,所以把它們送回主頁}

//我們創建壹個虛構的類頁面的對象,現在//適度地防止邪惡的用戶輸入$ obj = new Page

$ content = $ obj-& gt;fetch page($ PID);

//現在我們有了壹堆顯示頁面的PHP?& gt

妳需要做的就是用strlen()檢查變量的長度是否非零;如果是這樣,請使用全數字正則表達式來確保數據元素有效。如果PID包含字母、斜線、點或任何類似十六進制的東西,這個例程會捕獲它,並屏蔽用戶活動的頁面。如果您觀察Page類背後的情況,您會發現有安全意識的PHP開發人員對用戶輸入$pid進行了轉義,從而保護了fetchPage()方法,如下所示:

清單11。對fetchPage()方法進行轉義。

復制代碼代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

課程頁面{

函數提取頁面($pid){

$sql = "從pid= ' "的頁面中選擇pid、標題、desc、千瓦、內容、狀態。mysql_real_escape_string($pid)。”'";}

}

& gt

您可能會問,“如果您已經確保PID是壹個數字,為什麽還要對它進行轉義呢?”因為不知道fetchPage()方法會用到多少不同的上下文和情況。調用這個方法的地方都必須保護它,方法中的轉義體現了深度防禦的意思。

如果用戶試圖輸入很長的數字,例如1000個字符,並試圖發起緩沖區溢出攻擊,會發生什麽情況?下壹節將更詳細地討論這個問題,但是現在您可以添加另壹個檢查來確保輸入的PID具有正確的長度。您知道數據庫中pid字段的最大長度是5位數,因此您可以添加以下檢查。

清單12。使用正則表達式和長度檢查來限制GET變量的復制代碼。代碼如下:

& lt?服務器端編程語言(Professional Hypertext Preprocessor的縮寫)

$ PID = $ _ GET[' PID '];

if(strlen $ PID)){

如果(!ereg("^[0-9]+$",$pid)& amp;& ampstrlen($pid)>5){//做壹些適當的事情,比如讓他們退出或者把他們送回主頁}

}否則{

//清空$pid,所以把它們送回主頁}

//我們創建壹個虛構類頁面的對象,它現在//更加不受邪惡用戶輸入$obj = new Page的影響;

$ content = $ obj-& gt;fetch page($ PID);

//現在我們有了壹堆顯示頁面的PHP?& gt

現在,沒有人能把壹個5000位的數字塞進數據庫應用程序中——至少在涉及GET字符串的地方沒有。想象壹下,壹個黑客在試圖突破妳的應用程序而受挫時,咬牙切齒的樣子!而且由於關閉了報錯功能,黑客進行偵察的難度更大。

緩沖區溢出攻擊

緩沖區溢出攻擊試圖使PHP應用程序(或者更準確地說,Apache或底層操作系統)中的內存分配緩沖區溢出。請記住,您可能用PHP之類的高級語言編寫Web應用程序,但您最終會調用C(在Apache的情況下)。像大多數低級語言壹樣,C對內存分配有嚴格的規則。

緩沖區溢出攻擊向緩沖區發送大量數據,導致部分數據溢出到相鄰的內存緩沖區,從而破壞緩沖區或重寫邏輯。這可能導致拒絕服務、損壞數據或在遠程服務器上執行惡意代碼。

防止緩沖區溢出攻擊的唯壹方法是檢查所有用戶輸入的長度。例如,如果有壹個表單元素需要用戶的名字,那麽向該字段添加壹個值為40的maxlength屬性,並在後端用substr()檢查它。清單13給出了表單和PHP代碼的簡短示例。