PHP程式碼審計

apachecn_飛龍發表於2016-02-19

目錄

    1. 概述
    1. 輸入驗證和輸出顯示 3
      • 2.1 命令注入 4
      • 2.2 跨站指令碼 4
      • 2.3 檔案包含 5
      • 2.4 程式碼注入 5
      • 2.5 SQL隱碼攻擊 6
      • 2.6 XPath注入 6
      • 2.7 HTTP響應拆分 6
      • 2.8 檔案管理 6
      • 2.9 檔案上傳 7
      • 2.10 變數覆蓋 7
      • 2.11 動態函式 7
    1. 會話安全 8
      • 3.1 HTTPOnly設定 8
      • 3.2 domain設定 8
      • 3.3 path設定 8
      • 3.4 cookies持續時間 8
      • 3.5 secure設定 8
      • 3.6 session固定 9
      • 3.7 CSRF 9
    1. 加密 9
      • 4.1 明文儲存密碼 9
      • 4.2 密碼弱加密 9
      • 4.3 密碼儲存在攻擊者能訪問到的檔案 9
    1. 認證和授權 10
      • 5.1 使用者認證 10
      • 5.2 函式或檔案的未認證呼叫 10
      • 5.3 密碼硬編碼 10
    1. 隨機函式 10
      • 6.1 rand() 10
      • 6.2 mt_srand()和mt_rand() 11
    1. 特殊字元和多位元組編碼 11
      • 7.1 多位元組編碼 11
    1. PHP危險函式 11
      • 8.1 緩衝區溢位 11
      • 8.2 session_destroy()刪除檔案漏洞 12
      • 8.3 unset()-zend_hash_del_key_or_index漏洞 12
    1. 資訊洩露 13
      • 9.1 phpinfo 13
    1. PHP環境 13
      • 10.1 open_basedir設定 13
      • 10.2 allow_url_fopen設定 13
      • 10.3 allow_url_include設定 13
      • 10.4 safe_mode_exec_dir設定 14
      • 10.5 magic_quote_gpc設定 14
      • 10.6 register_globals設定 14
      • 10.7 safe_mode設定 14
      • 10.8 session_use_trans_sid設定 14
      • 10.9 display_errors設定 14
      • 10.10 expose_php設定 14

1.概述

程式碼稽核,是對應用程式原始碼進行系統性檢查的工作。它的目的是為了找到並且修復應用程式在開發階段存在的一些漏洞或者程式邏輯錯誤,避免程式漏洞被非法利用給企業帶來不必要的風險。

程式碼稽核不是簡單的檢查程式碼,稽核程式碼的原因是確保程式碼能安全的做到對資訊和資源進行足夠的保護,所以熟悉整個應用程式的業務流程對於控制潛在的風險是非常重要的。稽核人員可以使用類似下面的問題對開發者進行訪談,來收集應用程式資訊。

應用程式中包含什麼型別的敏感資訊,應用程式怎麼保護這些資訊的?

應用程式是對內提供服務,還是對外?哪些人會使用,他們都是可信使用者麼?

應用程式部署在哪裡?

應用程式對於企業的重要性?

最好的方式是做一個checklist,讓開發人員填寫。Checklist能比較直觀的反映應用程式的資訊和開發人員所做的編碼安全,它應該涵蓋可能存在嚴重漏洞的模組,例如:資料驗證、身份認證、會話管理、授權、加密、錯誤處理、日誌、安全配置、網路架構。

2.輸入驗證和輸出顯示

大多數漏洞的形成原因主要都是未對輸入資料進行安全驗證或對輸出資料未經過安全處理,比較嚴格的資料驗證方式為:

  1. 對資料進行精確匹配
  2. 接受白名單的資料
  3. 拒絕黑名單的資料
  4. 對匹配黑名單的資料進行編碼

在PHP中可由使用者輸入的變數列表如下:

  • $_SERVER
  • $_GET
  • $_POST
  • $_COOKIE
  • $_REQUEST
  • $_FILES
  • $_ENV
  • $_HTTP_COOKIE_VARS
  • $_HTTP_ENV_VARS
  • $_HTTP_GET_VARS
  • $_HTTP_POST_FILES
  • $_HTTP_POST_VARS
  • $_HTTP_SERVER_VARS

我們應該對這些輸入變數進行檢查

2.1 命令注入

PHP執行系統命令可以使用以下幾個函式:system、exec、passthru、“、shell_exec、popen、proc_open、pcntl_exec

我們通過在全部程式檔案中搜尋這些函式,確定函式的引數是否會因為外部提交而改變,檢查這些引數是否有經過安全處理。

防範方法:

  1. 使用自定義函式或函式庫來替代外部命令的功能
  2. 使用escapeshellarg函式來處理命令引數
  3. 使用safe_mode_exec_dir指定可執行檔案的路徑

2.2 跨站指令碼

反射型跨站常常出現在使用者提交的變數接受以後經過處理,直接輸出顯示給客戶端;儲存型跨站常常出現在使用者提交的變數接受過經過處理後,儲存在資料庫裡,然後又從資料庫中讀取到此資訊輸出到客戶端。輸出函式經常使用:echo、print、 printf、vprintf、< %=$test%>

對於反射型跨站,因為是立即輸出顯示給客戶端,所以應該在當前的php頁面檢查變數被客戶提交之後有無立即顯示,在這個過程中變數是否有經過安全檢查。

對於儲存型跨站,檢查變數在輸入後入庫,又輸出顯示的這個過程中,變數是否有經過安全檢查。

防範方法:

  1. 如果輸入資料只包含字母和數字,那麼任何特殊字元都應當阻止
  2. 對輸入的資料經行嚴格匹配,比如郵件格式,使用者名稱只包含英文或者中文、下劃線、連字元
  3. 對輸出進行HTML編碼,編碼規範
< < > >
( (
) )
# #
& &
” “
‘ ‘
` %60

2.3 檔案包含

PHP可能出現檔案包含的函式:include、include_once、require、require_once、show_source、highlight_file、readfile、file_get_contents、fopen、file

防範方法:

  1. 對輸入資料進行精確匹配,比如根據變數的值確定語言en.php、cn.php,那麼這兩個檔案放在同一個目錄下’language/’.$_POST[‘lang’].’.php’,那麼檢查提交的資料是否是en或者cn是最嚴格的,檢查是否只包含字母也不錯
  2. 通過過濾引數中的/、..等字元

2.4 程式碼注入

PHP可能出現程式碼注入的函式:eval、preg_replace+/e、assert、call_user_func、call_user_func_array、create_function

查詢程式中程式中使用這些函式的地方,檢查提交變數是否使用者可控,有無做輸入驗證

防範方法:

  1. 輸入資料精確匹配
  2. 白名單方式過濾可執行的函式

2.5 SQL隱碼攻擊

SQL隱碼攻擊因為要運算元據庫,所以一般會查詢SQL語句關鍵字:insert、delete、update、select,檢視傳遞的變數引數是否使用者可控制,有無做過安全處理

防範方法:

使用引數化查詢

2.6 XPath注入

Xpath用於操作xml,我們通過搜尋xpath來分析,提交給xpath函式的引數是否有經過安全處理

防範方法:

對於資料進行精確匹配

2.7 HTTP響應拆分

PHP中可導致HTTP響應拆分的情況為:使用header函式和使用$_SERVER變數。注意PHP的高版本會禁止HTTP表頭中出現換行字元,這類可以直接跳過本測試。

防範方法:

  1. 精確匹配輸入資料
  2. 檢測輸入輸入中如果有

    ,直接拒絕

2.8 檔案管理

PHP的用於檔案管理的函式,如果輸入變數可由使用者提交,程式中也沒有做資料驗證,可能成為高危漏洞。我們應該在程式中搜尋如下函式:copy、rmdir、unlink、delete、fwrite、chmod、fgetc、 fgetcsv、fgets、fgetss、file、file_get_contents、fread、readfile、ftruncate、 file_put_contents、fputcsv、fputs,但通常PHP中每一個檔案操作函式都可能是危險的。

http://ir.php.net/manual/en/ref.filesystem.php

防範方法:

  1. 對提交資料進行嚴格匹配
  2. 限定檔案可操作的目錄

2.9 檔案上傳

PHP檔案上傳通常會使用move_uploaded_file,也可以找到檔案上傳的程式進行具體分析

防範方式:

  1. 使用白名單方式檢測檔案字尾
  2. 上傳之後按時間能演算法生成檔名稱
  3. 上傳目錄指令碼檔案不可執行
  4. 注意%00截斷

2.10 變數覆蓋

PHP變數覆蓋會出現在下面幾種情況:

1.遍歷初始化變數

例:

foreach($_GET as $key => $value)
$$key = $value;

2.函式覆蓋變數:parse_str、mb_parse_str、import_request_variables

3.Register_globals=ON時,GET方式提交變數會直接覆蓋

防範方法:

  1. 設定Register_globals=OFF
  2. 不要使用這些函式來獲取變數

2.11 動態函式

當使用動態函式時,如果使用者對變數可控,則可導致攻擊者執行任意函式。

例:

< ?php $myfunc = $_GET[`myfunc`]; $myfunc(); ?>

防禦方法:

不要這樣使用函式

3.會話安全

3.1 HTTPOnly設定

session.cookie_httponly = ON時,客戶端指令碼(JavaScript等)無法訪問該cookie,開啟該指令可以有效預防通過XSS攻擊劫持會話ID

3.2 domain設定

檢查session.cookie_domain是否只包含本域,如果是父域,則其他子域能夠獲取本域的cookies

3.3 path設定

檢查session.cookie_path,如果網站本身應用在/app,則path必須設定為/app/,才能保證安全

3.4 cookies持續時間

檢查session.cookie_lifetime,如果時間設定過程過長,即使使用者關閉瀏覽器,攻擊者也會危害到帳戶安全

3.5 secure設定

如果使用HTTPS,那麼應該設定session.cookie_secure=ON,確保使用HTTPS來傳輸cookies

3.6 session固定

如果當許可權級別改變時(例如核實使用者名稱和密碼後,普通使用者提升到管理員),我們就應該修改即將重新生成的會話ID,否則程式會面臨會話固定攻擊的風險。

3.7 CSRF

跨站請求偽造攻擊,是攻擊者偽造一個惡意請求連結,通過各種方式讓正常使用者訪問後,會以使用者的身份執行這些惡意的請求。我們應該對比較重要的程式模組,比如修改使用者密碼,新增使用者的功能進行審查,檢查有無使用一次性令牌防禦csrf攻擊。

4.加密

4.1 明文儲存密碼

採用明文的形式儲存密碼會嚴重威脅到使用者、應用程式、系統安全。

4.2 密碼弱加密

使用容易破解的加密演算法,MD5加密已經部分可以利用md5破解網站來破解

4.3 密碼儲存在攻擊者能訪問到的檔案

例如:儲存密碼在txt、ini、conf、inc、xml等檔案中,或者直接寫在HTML註釋中

5.認證和授權

5.1 使用者認證

檢查程式碼進行使用者認證的位置,是否能夠繞過認證,例如:登入程式碼可能存在表單注入。

檢查登入程式碼有無使用驗證碼等,防止暴力破解的手段

5.2 函式或檔案的未認證呼叫

一些管理頁面是禁止普通使用者訪問的,有時開發者會忘記對這些檔案進行許可權驗證,導致漏洞發生

某些頁面使用引數呼叫功能,沒有經過許可權驗證,比如index.php?action=upload

5.3 密碼硬編碼

有的程式會把資料庫連結賬號和密碼,直接寫到資料庫連結函式中。

6.隨機函式

6.1 rand()

rand()最大隨機數是32767,當使用rand處理session時,攻擊者很容易破解出session,建議使用mt_rand()

6.2 mt_srand()和mt_rand()

PHP4和PHP5<5.2.6,這兩個函式處理資料是不安全的。在web應用中很多使用mt_rand來處理隨機的session,比如密碼找回功能等,這樣的後果就是被攻擊者惡意利用直接修改密碼。

7.特殊字元和多位元組編碼

7.1 多位元組編碼

8.PHP危險函式

8.1 緩衝區溢位

confirm_phpdoc_compiled

影響版本:

phpDocumentor phpDocumentor 1.3.1

phpDocumentor phpDocumentor 1.3 RC4

phpDocumentor phpDocumentor 1.3 RC3

phpDocumentor phpDocumentor 1.2.3

phpDocumentor phpDocumentor 1.2.2

phpDocumentor phpDocumentor 1.2.1

phpDocumentor phpDocumentor 1.2

mssql_pconnect/mssql_connect

影響版本:PHP < = 4.4.6

crack_opendict

影響版本:PHP = 4.4.6

snmpget

影響版本:PHP <= 5.2.3

ibase_connect

影響版本:PHP = 4.4.6

unserialize

影響版本:PHP 5.0.2、PHP 5.0.1、PHP 5.0.0、PHP 4.3.9、PHP 4.3.8、PHP 4.3.7、PHP 4.3.6、PHP 4.3.3、PHP 4.3.2、PHP 4.3.1、PHP 4.3.0、PHP 4.2.3、PHP 4.2.2、PHP 4.2.1、PHP 4.2.0、PHP 4.2-dev、PHP 4.1.2、PHP 4.1.1、PHP 4.1.0、PHP 4.1、PHP 4.0.7、PHP 4.0.6、PHP 4.0.5、PHP 4.0.4、PHP 4.0.3pl1、PHP 4.0.3、PHP 4.0.2、PHP 4.0.1pl2、PHP 4.0.1pl1、PHP 4.0.1

8.2 session_destroy()刪除檔案漏洞

影響版本:不祥,需要具體測試

測試程式碼如下:

01  <?php
02  session_save_path(‘./’);
03  session_start();
04  if($_GET[‘del’]) {
05  session_unset();
06  session_destroy();
07  }else{
08  $_SESSION[‘do’]=1;
09  echo(session_id());
10  print_r($_SESSION);
11  }
12  ?>

當我們提交cookieHPSESSIONID=/../1.php,相當於刪除了此檔案

8.3 unset()-zend_hash_del_key_or_index漏洞

zend_hash_del_key_or_index PHP4小於4.4.3和PHP5小於5.1.3,可能會導致zend_hash_del刪除了錯誤的元素。當PHP的unset()函式被呼叫時,它會阻止變數被unset。

9.資訊洩露

9.1 phpinfo

如果攻擊者可以瀏覽到程式中呼叫phpinfo顯示的環境資訊,會為進一步攻擊提供便利

10.PHP環境

10.1 open_basedir設定

open_basedir能限制應用程式能訪問的目錄,檢查有沒有對open_basedir進行設定,當然有的通過web伺服器來設定,例如:apache的php_admin_value,nginx+fcgi通過conf來控制php設定

10.2 allow_url_fopen設定

如果allow_url_fopen=ON,那麼php可以讀取遠端檔案進行操作,這個容易被攻擊者利用

10.3 allow_url_include設定

如果allow_url_include=ON,那麼php可以包含遠端檔案,會導致嚴重漏洞

10.4 safe_mode_exec_dir設定

這個選項能控制php可呼叫的外部命令的目錄,如果PHP程式中有呼叫外部命令,那麼指定外部命令的目錄,能控制程式的風險

10.5 magic_quote_gpc設定

這個選項能轉義提交給引數中的特殊字元,建議設定magic_quote_gpc=ON

10.6 register_globals設定

開啟這個選項,將導致php對所有外部提交的變數註冊為全域性變數,後果相當嚴重

10.7 safe_mode設定

safe_mode是PHP的重要安全特性,建議開啟

10.8 session_use_trans_sid設定

如果啟用 session.use_trans_sid,會導致 PHP 通過 URL 傳遞會話 ID,這樣一來,攻擊者就更容易劫持當前會話,或者欺騙使用者使用已被攻擊者控制的現有會話。

10.9 display_errors設定

如果啟用此選項,PHP將輸出所有的錯誤或警告資訊,攻擊者能利用這些資訊獲取web根路徑等敏感資訊

10.10 expose_php設定

如果啟用 expose_php 選項,那麼由 PHP 直譯器生成的每個響應都會包含主機系統上所安裝的 PHP 版本。瞭解到遠端伺服器上執行的 PHP 版本後,攻擊者就能針對系統列舉已知的盜取手段,從而大大增加成功發動攻擊的機會。

參考文件:

https://www.fortify.com/vulncat/zh_CN/vulncat/index.html

http://secinn.appspot.com/pstzine/read?issue=3&articleid=6

http://riusksk.blogbus.com/logs/51538334.html

http://www.owasp.org/index.php/Category:OWASP_Code_Review_Project

《來文來源於DoDo》


相關文章