程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> PHP代碼審核的詳細介紹

PHP代碼審核的詳細介紹

編輯:PHP綜合

概述
代碼審核,是對應用程序源代碼進行系統性檢查的工作。它的目的是為了找到並且修復應用程序在開發階段存在的一些漏洞或者程序邏輯錯誤,避免程序漏洞被非法利用給企業帶來不必要的風險
代碼審核不是簡單的檢查代碼,審核代碼的原因是確保代碼能安全的做到對信息和資源進行足夠的保護,所以熟悉整個應用程序的業務流程對於控制潛在的風險是非常重要的。
審核人員可以使用類似下面的問題對開發者進行訪談,來收集應用程序信息。

應用程序中包含什麼類型的敏感信息,應用程序怎麼保護這些信息的?
應用程序是對內提供服務,還是對外?哪些人會使用,他們都是可信用戶麼?
應用程序部署在哪裡?
應用程序對於企業的重要性?

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

輸入驗證和輸出顯示
大多數漏洞的形成原因主要都是未對輸入數據進行安全驗證或對輸出數據未經過安全處理,比較嚴格的數據驗證方式為:對數據進行精確匹配
接受白名單的數據
拒絕黑名單的數據
對匹配黑名單的數據進行編碼

在 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
我們應該對這些輸入變量進行檢查

命令注入
安全威脅
命令注入攻擊是通過把HTML代碼輸入一個輸入機制(例如缺乏有效驗證限制的表格域)來改變網頁的動態生成的內容,而這樣就可能會導致惡意命令掌控用戶的電腦和他們的網絡。PHP執行系統命令可以使用以下幾個函數:system、exec、passthru、``、shell_exec、popen、proc_open、pcntl_exec,我們通過在全部程序文件中搜索這些函數,確定函數的參數是否會因為外部提交而改變,檢查這些參數是否有經過安全處理。
代碼示例
例1:
復制代碼 代碼如下:
//ex1.php
<?php
$dir = $_GET["dir"];
if (isset($dir))
{
echo "<pre>";
system("ls -al".$dir);
echo "</pre>";
}
?>

我們提交
復制代碼 代碼如下:
http:// localhost/ex1.php?dir=| cat /etc/passwd

提交以後,命令變成了
復制代碼 代碼如下:
system("ls -al | cat /etc/passwd");



防范方法
1、盡量不要執行外部命令
2、使用自定義函數或函數庫來替代外部命令的功能
3、使用escapeshellarg函數來處理命令參數
4、使用safe_mode_exec_dir指定可執行文件的路徑
esacpeshellarg函數會將任何引起參數或命令結束的字符轉義,單引號“'”,替換成“\'”,雙引號“"”,替換成“\"”,分號“;”替換成“\;”,  用safe_mode_exec_dir指定可執行文件的路徑,可以把會使用的命令提前放入此路徑內。
復制代碼 代碼如下:
safe_mode = On
safe_mode_exec_di r= /usr/local/php/bin/

跨站腳本威脅(Cross Site Scripting)
安全威脅
Cross Site Script(XSS),跨站腳本威脅。攻擊者利用應用程序的動態展示數據功能,在 html 頁面裡嵌入惡意代碼。當用戶浏覽該頁之時,這些嵌入在 html 中的惡意代碼會被
執行,用戶浏覽器被攻擊者控制,從而達到攻擊者的特殊目的。輸出函數經常使用:echo、print、printf、vprintf、<%=$test%>

跨站腳本攻擊有以下三種攻擊形式:
(1)  反射型跨站腳本攻擊
攻擊者會通過社會工程學手段,發送一個 URL 連接給用戶打開,在用戶打開頁面的同時,浏覽器會執行頁面中嵌入的惡意腳本。
(2)  存儲型跨站腳本攻擊
攻擊者利用 web 應用程序提供的錄入或修改數據功能,將數據存儲到服務器或用戶cookie 中,當其他用戶浏覽展示該數據的頁面時,浏覽器會執行頁面中嵌入的惡意腳本。所有浏覽者都會受到攻擊。
(3)  DOM 跨站攻擊

由於 html 頁面中,定義了一段 JS,根據用戶的輸入,顯示一段 html 代碼,攻擊者可以在輸入時,插入一段惡意腳本,最終展示時,會執行惡意腳本。DOM 跨站和以上兩個跨站攻擊的差別是,DOM 跨站是純頁面腳本的輸出,只有規范使用 JAVASCRIPT,才可以防御。

惡意攻擊者可以利用跨站腳本攻擊做到:
(1) 盜取用戶 cookie,偽造用戶身份登錄。
(2) 讓浏覽者被迫執行某頁面操作,以用戶身份向服務器發起請求,達到攻擊目的。
(3) 結合浏覽器漏洞,下載病毒木馬到浏覽者的計算機上執行。
(4) 衍生 URL 跳轉漏洞。
(5) 讓官方網站出現釣魚頁面。
(6) 蠕蟲攻擊
代碼示例
直接在 html 頁面展示“用戶可控數據”,將直接導致跨站腳本威脅。
復制代碼 代碼如下:
<?
echo    “<span>$newsname</span>”;
echo    “<a  href=“$gifurl”>$gifname</a>”;
echo    “<input  type=text  name=user  value=\”$username\”>”;
echo “<span  style=‘$stylelayout'>”.  htmlentities($context).”</span>”;
?>

這幾種顯示方式,都可能導致用戶浏覽器把“用戶可控數據”當成 JS/VBS 腳本執行,或頁面元素被“用戶可控數據”插入的頁面 HTML 代碼控制,從而造成攻擊。
解決方案
a) 在 HTML 中顯示“用戶可控數據”前,應該進行 htmlescape 轉義。
復制代碼 代碼如下:
htmlspecialchars($outputString,ENT_QUOTES);

進行 html 轉義應該按照以下列表進行轉義:
復制代碼 代碼如下:
   & --> &
   < --> <
   > --> >
   " --> "
   ' --> '

b) 在 javascript 中輸出的“用戶可控數據”,需要做 javascript escape 轉義。
需要轉義的字符包括:
復制代碼 代碼如下:
    / --> \/ 
    ' --> \' 
    " --> \" 
    \ --> \\ 

c) 對輸出到富文本中的“用戶可控數據”,做富文本安全過濾(允許用戶輸出 HTML 的情況),防止富文本編輯器中存在腳本性的 script 代碼。
SQL 注入(SQL Injection)

安全威脅
當應用程序將用戶輸入的內容,拼接到 SQL 語句中,一起提交給數據庫執行時,就會產生 SQL 注入威脅。由於用戶的輸入,也是 SQL 語句的一部分,所以攻擊者可以利用這部分可以控制的內容,注入自己定義的語句,改變 SQL 語句執行邏輯,讓數據庫執行任意自己需要的指令。通過控制部分 SQL 語句,攻擊者可以查詢數據庫中任何自己需要的數據,利用數據庫的一些特性,可以直接獲取數據庫服務器的系統權限。本來 SQL 注入攻擊需要攻擊者對 SQL 語句非常了解,所以對攻擊者的技術有一定要求。但是幾年前,已經出現了大量 SQL 注入利用工具,可以讓任何攻擊者,只要點幾下鼠標,就能達到攻擊效果,這使得 SQL 注入的威脅,極大增加。

SQL注入攻擊的一般步驟:
1、攻擊者訪問有SQL注入漏洞的站點,尋找注入點
2、攻擊者構造注入語句,注入語句和程序中的SQL語句結合生成新的sql語句
3、新的sql語句被提交到數據庫中執行 處理
4、數據庫執行了新的SQL語句,引發SQL注入攻擊



代碼示例
對於輸入檢查不充分,導致 SQL 語句將用戶提交的非法數據當作語句的一部分來執行。
示例:
復制代碼 代碼如下:
<?
$id=$_GET['id'];
$name=$_GET['name'];
$sql="select * from news where `id`=$id and `username`='$name' ";
?>

解決方案
a)安全配置與編碼方式,PHP 配置選項在 php.ini 文件中指定。下列配置方式能夠加強php 的安全性,使應用程序避免受到 sql injection 的攻擊。
 1) safe_mode=onPHP,將通過文件函數或其目錄檢查當前腳本的擁有者是否和將被操作的文件的擁有者相匹配 ,當前腳本擁有者和文件操作擁有者不匹配則為違法操作
 2) magic_quotes_gpc=on / off,如果該選項被激活,那麼請求參數中包含的任何單引號、雙引號、反斜線和空字符都會用一個反斜線自動轉義。
 3) magic_quotes_sybase=on/off,如果改選項被禁用,那麼 PHP 就會用一個單引號轉義所有的單引號。
驗證數字型的變量
$id=(int)$id;
注:PHP6 已經刪除 magic quotes 選項

b)使用預處理執行 SQL 語句,對所有傳入 SQL 語句中的變量,做綁定。這樣,用戶拼接進來的變量,無論內容是什麼,都會被當做替代符號“?”所替代的值,數據庫也不會
把惡意用戶拼接進來的數據,當做部分 SQL 語句去解析。示例:
復制代碼 代碼如下:
$stmt = mysqli_stmt_init($link);
if (mysqli_stmt_prepare($stmt, 'SELECT District FROM City WHERE Name=?'))
{
/* bind parameters for markers */
mysqli_stmt_bind_param($stmt, "s", $city);
/* execute query */
mysqli_stmt_execute($stmt);
/* bind result variables */
mysqli_stmt_bind_result($stmt, $district);
/* fetch value */
mysqli_stmt_fetch($stmt);
mysqli_stmt_close($stmt);
}
/* close connection */
mysqli_close($link);

文件上傳威脅(File Upload)
安全威脅
PHP 文件上傳漏洞主要在於驗證文件類型的時候沒處理好文件變量所帶來的攻擊,導致程序判斷邏輯被繞過,攻擊者上傳腳本文件被服務器解析,從而獲取 SHELL 或者上傳時
文件被任意拷貝,甚至上傳腳本木馬到 web 服務器上,直接控制 web 服務器。
代碼示例
處理用戶上傳文件請求的代碼,這段代碼沒有過濾文件擴展名。
復制代碼 代碼如下:
    <? 
    // oldUpload.php 
    if(isset($upload)  &&  $myfile  !=  "none“  &&  check($myfile_name))  { 
    copy($myfile, "/var/www/upload/".$myfile_name); 
    echo "文件".$file_name."上傳成功!點擊<a href=\"$PHP_SELF\">繼續上傳</a>"; 
    exit; 
    } 
    //checkUpload.php 
    $DeniedExtensions=array('html','htm','php','php2','php3','php4','php5','ph 
    tml','pwml','inc','asp','aspx','ascx','jsp','cfm','cfc','pl','bat','exe',' 
    com','dll','vbs','js','reg','cgi','htaccess','asis') ; 
    if($checkUpload($_FILE[‘myfile'][name],  $DeniedExtensions)){copy($_FILE[‘myfile'][tmp_name],'upload/'.$_FILE[‘myfile'][name]); 
    } 
    ?> 
    <title>文件上傳</title> 
    <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> 
    </head> 
    <body bgcolor="#FFFFFF"> 
    <form enctype="multipart/form-data" method="post"> 
    上傳文件: 
    <input  type="file"    name=“myfile"  size="30"> 
    <input type="submit" name="upload" value="上傳"> 
    </form> 
    </body> 
    </html> 

解決方案
處理用戶上傳文件,要做以下檢查:
(1) 檢測文件後綴名是否符合白名單規范。
(2) 將文件按照隨機文件名的形式,保存在服務器上。
(3) 上傳目錄腳本文件不可執行
(4) 注意%00 截斷
(5) 對於 jpg 文件,需要讀取文件內容,然後生成一個新的 jpg 文件進行保存
Cross-Site Request Forgery (CSRF)

安全威脅
Cross-Site Request Forgery(CSRF),偽造跨站請求。攻擊者在用戶浏覽網頁時,利用頁面元素(例如 img 的 src),強迫受害者的浏覽器向Web 應用程序發送一個改變用戶信息的請求。由於發生 CSRF 攻擊後,攻擊者是強迫用戶向服務器發送請求,所以會造成用戶信息被迫修改,更嚴重者引發蠕蟲攻擊。
CSRF 攻擊可以從站外和站內發起。從站內發起 CSRF 攻擊,需要利用網站本身的業務,比如“自定義頭像”功能,惡意用戶指定自己的頭像 URL 是一個修改用戶信息的鏈接,當其他已登錄用戶浏覽惡意用戶頭像時,會自動向這個鏈接發送修改信息請求。

從站外發送請求,則需要惡意用戶在自己的服務器上,放一個自動提交修改個人信息的htm 頁面,並把頁面地址發給受害者用戶,受害者用戶打開時,會發起一個請求。

如果惡意用戶能夠知道網站管理後台某項功能的 URL,就可以直接攻擊管理員,強迫管理員執行惡意用戶定義的操作。
代碼示例
 一個沒有 CSRF 安全防御的代碼如下:
復制代碼 代碼如下:
<?
$user=checkSQL($user);
$pass=checkSQL($pass);
$sql=“update  UserTB set  password=$user  Where  user=$pass”;
mysqli_stmt_execute($sql);
?>

代碼中接收用戶提交的參數“user,pass”,之後修改了該用戶的數據,一旦接收到一個用戶發來的請求,就執行修改操作。
  提交表單代碼:
復制代碼 代碼如下:
<form action="http://localhost/servlet/modify" method="POST">
<input name="email">
<input name="tel">
</form>

當用戶點提交時,就會觸發修改操作。
攻擊實例
如果“代碼示例”中的代碼,是 xxx.com 上的一個 web 應用,那麼惡意用戶為了攻擊 xxx.com 的登錄用戶,可以構造 2 個 HTML 頁面。
(1) 頁面 a.htm 中,iframe 一下 b.htm,把寬和高都設為 0。
復制代碼 代碼如下:
<iframe src="b.htm" width="0" height="0"></frame>

這是為了當攻擊發生時,受害用戶看不到提交成功結果頁面。
(2) 頁面 b.htm 中,有一個表單,和一段腳本,腳本的作用是,當頁面加載時,自動提交這個表單。
復制代碼 代碼如下:
<form id="modify" action="http://xxx.com/servlet/modify" method="POST">
<input name="email">
<input name="tel">
</form>
<script>
document.getElementById("modify").submit();
</script>

(3) 攻擊者只要把頁面 a.htm 放在自己的 web 服務器上,並發送給登錄用戶即可。用戶打開 a.htm 後,會自動提交表單,發送給 xxx.com 下的那個存在 CSRF 漏洞的web 應用,所以用戶的信息,就被迫修改了。

解決方案
CSRF 防御的原理是,在用戶登錄的時候,生成一個隨機的 token,將它存儲在 cookie中(默認情況,也可以放在 session 中),在生成表單時,生成一個隱藏域,隱藏域的值就等
於 token 的值。如果用戶提交這個表單,就可以在接收用戶請求的 web 應用中,判斷隱藏域的 TOKEN 值是否和用戶 COOKIE 中的 TOKEN 值一致,如果不一致或沒有這個值,就判
斷為 CSRF 攻擊。攻擊者無法預測每一個用戶登錄時生成的那個隨機 TOKEN 值,所以無法偽造這個參數。

常見問題
(1) 為什麼不直接驗證 referer?
因為還有站內發出的 csrf,並且 referer 是可以被篡改的,是不可靠的數據
(2) 如果先發生 xss 攻擊,攻擊者可以拿到用戶頁面的 token 怎麼辦?
無解,請先做好 xss 防范。
文件包含
PHP 可 能 出 現文 件 包 含 的 函 數: include、 include_once 、 require、 require_once 、show_source、highlight_file、readfile、file_get_contents、fopen、file
防范方法:
對輸入數據進行精確匹配,比如根據變量的值確定語言 en.php、cn.php,那麼這兩個文件放在同一個目錄下'language/'.$_POST[‘lang'].'.php',
那麼檢查提交的數據是否是 en 或者 cn 是最嚴格的,檢查是否只包含字母也不錯,通過過濾參數中的/、..等字符。
HTTP 響應拆分
PHP 中可導致 HTTP 響應拆分的情況為:使用 header 函數和使用$_SERVER 變量。注意PHP 的高版本會禁止 HTTP 表頭中出現換行字符,這類可以直接跳過本測試。
防范方法:
精確匹配輸入數據
檢測輸入輸入中如果有\r 或\n,直接拒絕
變量覆蓋
PHP 變量覆蓋會出現在下面幾種情況:
遍歷初始化變量
例:
復制代碼 代碼如下:
foreach($_GET as $key => $value)
$$key = $value;

函數覆蓋變量:parse_str、mb_parse_str、import_request_variables,Register_globals=ON 時,GET 方式提交變量會直接覆蓋
防范方法:
設置 Register_globals=OFF
不要使用這些函數來獲取變量
動態函數
當使用動態函數時,如果用戶對變量可控,則可導致攻擊者執行任意函數。
例:
復制代碼 代碼如下:
<?php
$myfunc=$_GET['myfunc'];
$myfunc();
?>

防御方法:
      不要這樣使用函數
會話安全
HTTPOnly 設置
session.cookie_httponly = ON 時,客戶端腳本(JavaScript 等)無法訪問該 cookie,打開該指令可以有效預防通過 XSS 攻擊劫持會話 ID
domain 設置
檢查 session.cookie_domain 是否只包含本域,如果是父域,則其他子域能夠獲取本域的cookies
path 設置
檢查 session.cookie_path,如果網站本身應用在/app,則 path 必須設置為/app/,才能保證安全
cookies 持續時間
檢查 session.cookie_lifetime,如果時間設置過程過長,即使用戶關閉浏覽器,攻擊者也會危害到帳戶安全
secure 設置
如果使用 HTTPS,那麼應該設置 session.cookie_secure=ON,確保使用 HTTPS 來傳輸cookies
session 固定
如果當權限級別改變時(例如核實用戶名和密碼後,普通用戶提升到管理員),我們就應該修改即將重新生成的會話 ID ,否則程序會面臨會話固定攻擊的風險。

加密
明文存儲密碼
采用明文的形式存儲密碼會嚴重威脅到用戶、應用程序、系統安全。
密碼弱加密
使用容易破解的加密算法,MD5加密已經部分可以利用 md5破解網站來破解
參考方案
復制代碼 代碼如下:
md5(md5($password).$salt)

密碼存儲在攻擊者能訪問到的文件
例如:保存密碼在 txt 、ini、conf、inc、xml 等文件中,或者直接寫在 HTML 注釋中

認證和授權
用戶認證
檢查代碼進行用戶認證的位置,是否能夠繞過認證,例如:登錄代碼可能存在表單注入。
檢查登錄代碼有無使用驗證碼等,防止暴力破解的手段
函數或文件的未認證調用

一些管理頁面是禁止普通用戶訪問的,有時開發者會忘記對這些文件進行權限驗證,導致漏洞發生
某些頁面使用參數調用功能,沒有經過權限驗證,比如 index.php?action=upload
密碼硬編碼

有的程序會把數據庫鏈接賬號和密碼,直接寫到數據庫鏈接函數中。
隨機函數
rand() VS mt_rand()
rand()最大隨機數是 32767,當使用 rand 處理 session 時,攻擊者很容易破解出session,建議使用mt_rand()。
代碼示例
復制代碼 代碼如下:
<?php
//on windows
print mt_getrandmax(); //2147483647
print getrandmax();// 32767
?>

可以看出 rand()最大的隨機數是 32767,這個很容易被我們暴力破解。
復制代碼 代碼如下:
<?php
$a= md5(rand());
for($i=0;$i<=32767;$i++){
if(md5($i) ==$a ) {
print $i."-->ok!!<br>";exit;
}else { print $i."<br>";}
}
?>

當我們的程序使用 rand 處理 session 時,攻擊者很容易暴力破解出你的 session,但是對於 mt_rand 是很難單純的暴力的。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved