<table width="100%" border="0" cellspacing="0" cellpadding="5" bgcolor="#649CCC"><tr valign="middle"><td align="left"> <p class="p_Heading1"><span class="f_Heading1">附錄B. 函數</span></p> </td> <td align="right"> <span style="font-size: 9pt"> <a href="introduction.htm">Top</a>? <a href="new_item53.htm">Previous</a>? <a href="new_item55.htm">Next</a> </span> </td> </tr></table>
<table width="100%" border="0" cellspacing="0" cellpadding="5"><tr valign="top"><td align="left"><p style="line-height: 1.50;">附錄B. 函數</p><p style="line-height: 1.50;"> ? 在我寫作本書的時候,http://php.net/quickref.php列出了共3917個函數,其中包括一些類似函數的語法結構,在此我不準備把它們從函數中區分開來,而是把它作為函數看待。</p><p style="line-height: 1.50;"> ? 由于函數數量很大,一一說明它們的正確及安全用法是不太可能的。在此我選出了我認為最需要注意的函數。選擇的標準包括使用的頻繁度、使用時的危險(安全)度及我本人的經驗。</p><p style="line-height: 1.50;"> ? 對于每一個列出的函數,我都會提供推薦的使用方法。在提出這些方法時,我會把安全作為重點考慮。請在實際使用時根據你的需求進行相應調整。</p><p style="line-height: 1.50;"> ? 當一個函數與另一個有相同的風險時,我會給出參見另一個函數的信息,而不是多余地再次描述一遍。</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.1. eval( )</p><p style="line-height: 1.50;"> ? eval( )函數用于對一個字符串以PHP語句方式解析運行。如:</p><p style="line-height: 1.50;"> ? <?php</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $name = 'Chris';</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $string = 'echo "Hello, $name";';</p><p style="line-height: 1.50;"> ? eval($string);</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? ?></p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? 上例中會把$string作為PHP語句來運行,因此等價于:</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? <?php</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $name = 'Chris';</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? echo "Hello, $name";</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? ?></p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? 雖然eval( )非常有用,但是當使用了被污染數據時會非常危險。例如,在下例中,如果$name是被污染的,攻擊者可以任意運行PHP代碼:</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? <?php</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $name = $_GET['name'];</p><p style="line-height: 1.50;"> ? eval($name);</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? ?></p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? 當你無法確信以PHP方式解釋的字符串是否使用被污染數據時,以及在可能的情況下,我推薦你避免使用eval( )。在安全審查和同行評審中,應重點檢查該函數。</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.2. exec( )</p><p style="line-height: 1.50;"> ? 第6章中已提到,執行shell命令是非常危險的操作,在構造shell命令時使用被污染數據會導致命令注入漏洞。</p><p style="line-height: 1.50;"> ? 盡量避免使用shell命令函數,但當你需要用它們時,請確信構造shell命令時只使用過濾及轉義過的數據。</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? <?php</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $clean = array();</p><p style="line-height: 1.50;"> ? $shell = array();</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? /* Filter Input ($command, $argument) */</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $shell['command'] = escapeshellcmd($clean['command']);</p><p style="line-height: 1.50;"> ? $shell['argument'] = escapeshellarg($clean['argument']);</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $last = exec("{$shell['command']} {$shell['argument']}", $output, $return);</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? ?></p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.3. file( )</p><p style="line-height: 1.50;"> ? file( )函數是我喜歡使用的讀文件方法之一。它會讀取文件的每一行作為返回數組的元素。特別方便的一點是,你不需要提供一個文件句柄——你提供文件名,它會為你做好一切:</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? <?php</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $contents = file('/tmp/file.txt');</p><p style="line-height: 1.50;"> ? print_r($contents);</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? ?></p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? 如果上面的文件有兩行,則會產生類似如下的輸出:</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? Array</p><p style="line-height: 1.50;"> ? (</p><p style="line-height: 1.50;"> ? ? ? [0] => This is line one.</p><p style="line-height: 1.50;"> ? ? ? [1] => This is line two.</p><p style="line-height: 1.50;"> ? )</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? 使用file( )函數不是特別危險,但當你在allow_url_fopen選項打開的情況下使用時,它就能讀取許多不同類型的資源如一個遠程網站的內容:</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? <?php</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $contents = file('http://example.org/');</p><p style="line-height: 1.50;"> ? print_r($contents);</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? ?></p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? 輸出如下 (有刪節):</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? Array</p><p style="line-height: 1.50;"> ? (</p><p style="line-height: 1.50;"> ? ? ? [0] => <html></p><p style="line-height: 1.50;"> ? ? ? [1] => <head></p><p style="line-height: 1.50;"> ? ? ? [2] => <title>Example Web Page</title></p><p style="line-height: 1.50;"> ? ? ? [3] => </head></p><p style="line-height: 1.50;"> ? ? ? [4] => <body></p><p style="line-height: 1.50;"> ? ? ? ...</p><p style="line-height: 1.50;"> ? ? ? [11] => </body></p><p style="line-height: 1.50;"> ? ? ? [12] => </html></p><p style="line-height: 1.50;"> ? )</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? 如果file()函數調用的文件名是由被污染數據構造的,則其內容也應被看成是被污染的。這是因為使用被污染數據構造文件名可能會導致你打開一個有惡意數據的遠程網站。一旦你把數據保存在一個變量中,危險就大幅增加了:</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? <?php</p><p style="line-height: 1.50;"> ? $tainted = file($_POST['filename']);</p><p style="line-height: 1.50;"> ? ?></p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? $tainted數組中的每個元素與$_POST['filename']有相同的危險性——它是輸入并必須要進行過濾。</p><p style="line-height: 1.50;"> ? 在這里,其行為有可能是意想不到的——$_POST['filename']的誤用可以改變file()函數的行為,因此它可以指向一個遠程資源而不是本地文件。</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.4. file_get_contents( )</p><p style="line-height: 1.50;"> ? 參見 "file( )."</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.5. fopen( )</p><p style="line-height: 1.50;"> ? 參見 "file( )."</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.6. include</p><p style="line-height: 1.50;"> ? 如第5章所述,include在組織化與模塊化的軟件設計中被普遍使用,是非常有必要的。但是,不正確的使用include會造成一個重大的代碼注入安全漏洞。</p><p style="line-height: 1.50;"> ? 在include語句中只使用已過濾數據是非常有必要的。在安全審查和同行評審中,應重點檢查該函數。</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.7. passthru( )</p><p style="line-height: 1.50;"> ? 見"exec( )."</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.8. phpinfo( )</p><p style="line-height: 1.50;"> ? phpinfo( )會輸出有關PHP信息的頁面——運行的版本號,配置信息等等。由于phpinfo( )的輸出提供了非常多的信息,我建議限制對任何使用該函數的資源的訪問。</p><p style="line-height: 1.50;"> ? 如果你使用的第八章中的技巧來保護數據庫驗證信息,則需要確認訪問者不能看到由phpinfo( )形成的輸出信息,這是由于它會暴露超級全局數組$_SERVER的內容。</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.9. popen( )</p><p style="line-height: 1.50;"> ? 參見"exec( )."</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.10. preg_replace( )</p><p style="line-height: 1.50;"> ? preg_replace( )用于對符合正則表達式的字符串進行替換。在某些情況下,使用被污染數據構造正則表達式部分會非常危險,因為它的e修飾符會導致在替換時把用于替換的參數作為PHP代碼來對待。例如(本例為譯者所加):</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"><?php</p><p style="line-height: 1.50;">$str = "abcdef";</p><p style="line-height: 1.50;">$se = "len";</p><p style="line-height: 1.50;">$reg = "/abc/e";</p><p style="line-height: 1.50;">echo preg_replace($reg,"strlen(\$se)",$str);</p><p style="line-height: 1.50;">?></p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">會輸出如下字串:</p><p style="line-height: 1.50;">3def</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;"> ? 當使用了e修飾符,不管是否有意為之,它會帶來與eval()相同的風險。在安全審查和同行評審中,應重點檢查該函數。</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.11. proc_open( )</p><p style="line-height: 1.50;"> ? 參見 "exec( )."</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.12. readfile( )</p><p style="line-height: 1.50;"> ? 參見 "file( )."</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.13. require</p><p style="line-height: 1.50;"> ? 參見 "include."</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.14. shell_exec( )</p><p style="line-height: 1.50;"> ? 參見 "exec( )."</p><p style="line-height: 1.50;">?</p><p style="line-height: 1.50;">B.15. system( )</p><p style="line-height: 1.50;"> ? 參見 "exec( )."</p><p style="line-height: 1.50;">?</p><hr noshade="noshade" size="1"/><p style="line-height: 1.50;">?</p></td></tr></table>
- 第一章 簡介
- 1.1.PHP功能
- 1.1.1. 全局變量注冊
- 1.1.2. 錯誤報告
- 1.2.原則
- 1.2.1. 深度防范
- 1.2.2. 最小權限
- 1.2.3. 簡單就是美
- 1.2.4. 暴露最小化
- 1.3. 方法
- 1.3.1. 平衡風險與可用性
- 1.3.2. 跟蹤數據
- 1.3.3. 過濾輸入
- 1.3.4. 輸出轉義
- 第二章 表單及URL
- 2.1. 表單與數據
- 2.2. 語義URL攻擊
- 2.3. 文件上傳攻擊
- 2.4. 跨站腳本攻擊
- 2.5. 跨站請求偽造
- 2.6. 欺騙表單提交
- 2.7. HTTP請求欺騙
- 第三章 數據庫及SQL
- 3.1. 訪問權限暴露
- 3.2. SQL 注入
- 3.3. 數據的暴露
- 第四章 會話與 Cookies
- 4.1. Cookie 盜竊
- 4.2. 會話數據暴露
- 4.3. 會話固定
- 4.4. 會話劫持
- 第五章 包含
- 5.1. 源碼暴露
- 5.2. 后門URL
- 5.3. 文件名操縱
- 5.4. 代碼注入
- 第六章 文件與命令
- 6.1. 文件系統跨越
- 6.2. 遠程文件風險
- 6.3. 命令注入
- 第七章 驗證與授權
- 7.1. 暴力攻擊
- 7.2. 密碼嗅探
- 7.3. 重播攻擊
- 7.4. 永久登錄
- 第八章 共享主機
- 8.1. 源碼暴露
- 8.2. 會話數據暴露
- 8.3. 會話注入
- 8.4. 文件系統瀏覽
- 8.5. 安全模式
- 附錄 A. 配置選項
- 附錄B. 函數
- 附錄C. 加密