|
概述
代碼審核,是對應(yīng)用程序源代碼進行系統(tǒng)性檢查的工作。它的目的是為了找到并且修復(fù)應(yīng)用程序在開發(fā)階段存在的一些漏洞或者程序邏輯錯誤,避免程序漏洞被非法利用給企業(yè)帶來不必要的風(fēng)險
代碼審核不是簡單的檢查代碼,審核代碼的原因是確保代碼能安全的做到對信息和資源進行足夠的保護,所以熟悉整個應(yīng)用程序的業(yè)務(wù)流程對于控制潛在的風(fēng)險是非常重要的。
審核人員可以使用類似下面的問題對開發(fā)者進行訪談,來收集應(yīng)用程序信息。
應(yīng)用程序中包含什么類型的敏感信息,應(yīng)用程序怎么保護這些信息的?
應(yīng)用程序是對內(nèi)提供服務(wù),還是對外?哪些人會使用,他們都是可信用戶么?
應(yīng)用程序部署在哪里?
應(yīng)用程序?qū)τ谄髽I(yè)的重要性?
最好的方式是做一個 checklist,讓開發(fā)人員填寫。Checklist 能比較直觀的反映應(yīng)用程序的信息和開發(fā)人員所做的編碼安全,它應(yīng)該涵蓋可能存在嚴(yán)重漏洞的模塊,例如:數(shù)據(jù)驗證、身份認(rèn)證、會話管理、授權(quán)、加密、錯誤處理、日志、安全配置、網(wǎng)絡(luò)架構(gòu)。
輸入驗證和輸出顯示
大多數(shù)漏洞的形成原因主要都是未對輸入數(shù)據(jù)進行安全驗證或?qū)敵鰯?shù)據(jù)未經(jīng)過安全處理,比較嚴(yán)格的數(shù)據(jù)驗證方式為:對數(shù)據(jù)進行精確匹配
接受白名單的數(shù)據(jù)
拒絕黑名單的數(shù)據(jù)
對匹配黑名單的數(shù)據(jù)進行編碼
在 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
我們應(yīng)該對這些輸入變量進行檢查
命令注入
安全威脅
命令注入攻擊是通過把HTML代碼輸入一個輸入機制(例如缺乏有效驗證限制的表格域)來改變網(wǎng)頁的動態(tài)生成的內(nèi)容,而這樣就可能會導(dǎo)致惡意命令掌控用戶的電腦和他們的網(wǎng)絡(luò)。php執(zhí)行系統(tǒng)命令可以使用以下幾個函數(shù):system、exec、passthru、``、shell_exec、popen、proc_open、pcntl_exec,我們通過在全部程序文件中搜索這些函數(shù),確定函數(shù)的參數(shù)是否會因為外部提交而改變,檢查這些參數(shù)是否有經(jīng)過安全處理。
代碼示例
例1:
復(fù)制代碼 代碼如下:
//ex1.php
<?php
$dir = $_GET["dir"];
if (isset($dir))
{
echo "<pre>";
system("ls -al".$dir);
echo "</pre>";
}
?>
我們提交
復(fù)制代碼 代碼如下:
http:// localhost/ex1.php?dir=| cat /etc/passwd
提交以后,命令變成了
復(fù)制代碼 代碼如下:
system("ls -al | cat /etc/passwd");

防范方法
1、盡量不要執(zhí)行外部命令
2、使用自定義函數(shù)或函數(shù)庫來替代外部命令的功能
3、使用escapeshellarg函數(shù)來處理命令參數(shù)
4、使用safe_mode_exec_dir指定可執(zhí)行文件的路徑
esacpeshellarg函數(shù)會將任何引起參數(shù)或命令結(jié)束的字符轉(zhuǎn)義,單引號“'”,替換成“/'”,雙引號“"”,替換成“/"”,分號“;”替換成“/;”, 用safe_mode_exec_dir指定可執(zhí)行文件的路徑,可以把會使用的命令提前放入此路徑內(nèi)。
復(fù)制代碼 代碼如下:
safe_mode = On
safe_mode_exec_di r= /usr/local/php/bin/
跨站腳本威脅(Cross Site Scripting)
安全威脅
Cross Site Script(XSS),跨站腳本威脅。攻擊者利用應(yīng)用程序的動態(tài)展示數(shù)據(jù)功能,在 html 頁面里嵌入惡意代碼。當(dāng)用戶瀏覽該頁之時,這些嵌入在 html 中的惡意代碼會被
執(zhí)行,用戶瀏覽器被攻擊者控制,從而達到攻擊者的特殊目的。輸出函數(shù)經(jīng)常使用:echo、print、printf、vprintf、<%=$test%>
跨站腳本攻擊有以下三種攻擊形式:
(1) 反射型跨站腳本攻擊
攻擊者會通過社會工程學(xué)手段,發(fā)送一個 URL 連接給用戶打開,在用戶打開頁面的同時,瀏覽器會執(zhí)行頁面中嵌入的惡意腳本。
(2) 存儲型跨站腳本攻擊
攻擊者利用 web 應(yīng)用程序提供的錄入或修改數(shù)據(jù)功能,將數(shù)據(jù)存儲到服務(wù)器或用戶cookie 中,當(dāng)其他用戶瀏覽展示該數(shù)據(jù)的頁面時,瀏覽器會執(zhí)行頁面中嵌入的惡意腳本。所有瀏覽者都會受到攻擊。
(3) DOM 跨站攻擊
由于 html 頁面中,定義了一段 JS,根據(jù)用戶的輸入,顯示一段 html 代碼,攻擊者可以在輸入時,插入一段惡意腳本,最終展示時,會執(zhí)行惡意腳本。DOM 跨站和以上兩個跨站攻擊的差別是,DOM 跨站是純頁面腳本的輸出,只有規(guī)范使用 JavaSCRIPT,才可以防御。
惡意攻擊者可以利用跨站腳本攻擊做到:
(1) 盜取用戶 cookie,偽造用戶身份登錄。
(2) 讓瀏覽者被迫執(zhí)行某頁面操作,以用戶身份向服務(wù)器發(fā)起請求,達到攻擊目的。
(3) 結(jié)合瀏覽器漏洞,下載病毒木馬到瀏覽者的計算機上執(zhí)行。
(4) 衍生 URL 跳轉(zhuǎn)漏洞。
(5) 讓官方網(wǎng)站出現(xiàn)釣魚頁面。
(6) 蠕蟲攻擊
代碼示例
直接在 html 頁面展示“用戶可控數(shù)據(jù)”,將直接導(dǎo)致跨站腳本威脅。
復(fù)制代碼 代碼如下:
<?
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>”;
?>
這幾種顯示方式,都可能導(dǎo)致用戶瀏覽器把“用戶可控數(shù)據(jù)”當(dāng)成 JS/VBS 腳本執(zhí)行,或頁面元素被“用戶可控數(shù)據(jù)”插入的頁面 HTML 代碼控制,從而造成攻擊。
解決方案
a) 在 HTML 中顯示“用戶可控數(shù)據(jù)”前,應(yīng)該進行 htmlescape 轉(zhuǎn)義。
復(fù)制代碼 代碼如下:
htmlspecialchars($outputString,ENT_QUOTES);
進行 html 轉(zhuǎn)義應(yīng)該按照以下列表進行轉(zhuǎn)義:
復(fù)制代碼 代碼如下:
& --> &
< --> <
> --> >
" --> "
' --> '
b) 在 Javascript 中輸出的“用戶可控數(shù)據(jù)”,需要做 Javascript escape 轉(zhuǎn)義。
需要轉(zhuǎn)義的字符包括:
復(fù)制代碼 代碼如下:
/ --> //
' --> /'
" --> /"
/ --> //
c) 對輸出到富文本中的“用戶可控數(shù)據(jù)”,做富文本安全過濾(允許用戶輸出 HTML 的情況),防止富文本編輯器中存在腳本性的 script 代碼。
SQL 注入(SQL Injection)
安全威脅
當(dāng)應(yīng)用程序?qū)⒂脩糨斎氲膬?nèi)容,拼接到 SQL 語句中,一起提交給數(shù)據(jù)庫執(zhí)行時,就會產(chǎn)生 SQL 注入威脅。由于用戶的輸入,也是 SQL 語句的一部分,所以攻擊者可以利用這部分可以控制的內(nèi)容,注入自己定義的語句,改變 SQL 語句執(zhí)行邏輯,讓數(shù)據(jù)庫執(zhí)行任意自己需要的指令。通過控制部分 SQL 語句,攻擊者可以查詢數(shù)據(jù)庫中任何自己需要的數(shù)據(jù),利用數(shù)據(jù)庫的一些特性,可以直接獲取數(shù)據(jù)庫服務(wù)器的系統(tǒng)權(quán)限。本來 SQL 注入攻擊需要攻擊者對 SQL 語句非常了解,所以對攻擊者的技術(shù)有一定要求。但是幾年前,已經(jīng)出現(xiàn)了大量 SQL 注入利用工具,可以讓任何攻擊者,只要點幾下鼠標(biāo),就能達到攻擊效果,這使得 SQL 注入的威脅,極大增加。
SQL注入攻擊的一般步驟:
1、攻擊者訪問有SQL注入漏洞的站點,尋找注入點
2、攻擊者構(gòu)造注入語句,注入語句和程序中的SQL語句結(jié)合生成新的sql語句
3、新的sql語句被提交到數(shù)據(jù)庫中執(zhí)行 處理
4、數(shù)據(jù)庫執(zhí)行了新的SQL語句,引發(fā)SQL注入攻擊
代碼示例
對于輸入檢查不充分,導(dǎo)致 SQL 語句將用戶提交的非法數(shù)據(jù)當(dāng)作語句的一部分來執(zhí)行。
示例:
復(fù)制代碼 代碼如下:
<?
$id=$_GET['id'];
$name=$_GET['name'];
$sql="select * from news where `id`=$id and `username`='$name' ";
?>
解決方案
a)安全配置與編碼方式,php 配置選項在 php.ini 文件中指定。下列配置方式能夠加強php 的安全性,使應(yīng)用程序避免受到 sql injection 的攻擊。
1) safe_mode=onphp,將通過文件函數(shù)或其目錄檢查當(dāng)前腳本的擁有者是否和將被操作的文件的擁有者相匹配 ,當(dāng)前腳本擁有者和文件操作擁有者不匹配則為違法操作
2) magic_quotes_gpc=on / off,如果該選項被激活,那么請求參數(shù)中包含的任何單引號、雙引號、反斜線和空字符都會用一個反斜線自動轉(zhuǎn)義。
3) magic_quotes_sybase=on/off,如果改選項被禁用,那么 php 就會用一個單引號轉(zhuǎn)義所有的單引號。
驗證數(shù)字型的變量
$id=(int)$id;
注:php6 已經(jīng)刪除 magic quotes 選項
b)使用預(yù)處理執(zhí)行 SQL 語句,對所有傳入 SQL 語句中的變量,做綁定。這樣,用戶拼接進來的變量,無論內(nèi)容是什么,都會被當(dāng)做替代符號“?”所替代的值,數(shù)據(jù)庫也不會
把惡意用戶拼接進來的數(shù)據(jù),當(dāng)做部分 SQL 語句去解析。示例:
復(fù)制代碼 代碼如下:
$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 文件上傳漏洞主要在于驗證文件類型的時候沒處理好文件變量所帶來的攻擊,導(dǎo)致程序判斷邏輯被繞過,攻擊者上傳腳本文件被服務(wù)器解析,從而獲取 SHELL 或者上傳時
文件被任意拷貝,甚至上傳腳本木馬到 web 服務(wù)器上,直接控制 web 服務(wù)器。
代碼示例
處理用戶上傳文件請求的代碼,這段代碼沒有過濾文件擴展名。
復(fù)制代碼 代碼如下:
<?
// oldUpload.php
if(isset($upload) && $myfile != "none“ && check($myfile_name)) {
copy($myfile, "/var/www/upload/".$myfile_name);
echo "文件".$file_name."上傳成功!點擊<a href=/"$php_SELF/">繼續(xù)上傳</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) 檢測文件后綴名是否符合白名單規(guī)范。
(2) 將文件按照隨機文件名的形式,保存在服務(wù)器上。
(3) 上傳目錄腳本文件不可執(zhí)行
(4) 注意%00 截斷
(5) 對于 jpg 文件,需要讀取文件內(nèi)容,然后生成一個新的 jpg 文件進行保存
Cross-Site Request Forgery (CSRF)
安全威脅
Cross-Site Request Forgery(CSRF),偽造跨站請求。攻擊者在用戶瀏覽網(wǎng)頁時,利用頁面元素(例如 img 的 src),強迫受害者的瀏覽器向Web 應(yīng)用程序發(fā)送一個改變用戶信息的請求。由于發(fā)生 CSRF 攻擊后,攻擊者是強迫用戶向服務(wù)器發(fā)送請求,所以會造成用戶信息被迫修改,更嚴(yán)重者引發(fā)蠕蟲攻擊。
CSRF 攻擊可以從站外和站內(nèi)發(fā)起。從站內(nèi)發(fā)起 CSRF 攻擊,需要利用網(wǎng)站本身的業(yè)務(wù),比如“自定義頭像”功能,惡意用戶指定自己的頭像 URL 是一個修改用戶信息的鏈接,當(dāng)其他已登錄用戶瀏覽惡意用戶頭像時,會自動向這個鏈接發(fā)送修改信息請求。
從站外發(fā)送請求,則需要惡意用戶在自己的服務(wù)器上,放一個自動提交修改個人信息的htm 頁面,并把頁面地址發(fā)給受害者用戶,受害者用戶打開時,會發(fā)起一個請求。
如果惡意用戶能夠知道網(wǎng)站管理后臺某項功能的 URL,就可以直接攻擊管理員,強迫管理員執(zhí)行惡意用戶定義的操作。
代碼示例
一個沒有 CSRF 安全防御的代碼如下:
復(fù)制代碼 代碼如下:
<?
$user=checkSQL($user);
$pass=checkSQL($pass);
$sql=“update UserTB set password=$user Where user=$pass”;
mysqli_stmt_execute($sql);
?>
代碼中接收用戶提交的參數(shù)“user,pass”,之后修改了該用戶的數(shù)據(jù),一旦接收到一個用戶發(fā)來的請求,就執(zhí)行修改操作。
提交表單代碼:
復(fù)制代碼 代碼如下:
<form action="http://localhost/servlet/modify" method="POST">
<input name="email">
<input name="tel">
</form>
當(dāng)用戶點提交時,就會觸發(fā)修改操作。
攻擊實例
如果“代碼示例”中的代碼,是 xxx.com 上的一個 web 應(yīng)用,那么惡意用戶為了攻擊 xxx.com 的登錄用戶,可以構(gòu)造 2 個 HTML 頁面。
(1) 頁面 a.htm 中,iframe 一下 b.htm,把寬和高都設(shè)為 0。
復(fù)制代碼 代碼如下:
<iframe src="b.htm" width="0" height="0"></frame>
這是為了當(dāng)攻擊發(fā)生時,受害用戶看不到提交成功結(jié)果頁面。
(2) 頁面 b.htm 中,有一個表單,和一段腳本,腳本的作用是,當(dāng)頁面加載時,自動提交這個表單。
復(fù)制代碼 代碼如下:
<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 服務(wù)器上,并發(fā)送給登錄用戶即可。用戶打開 a.htm 后,會自動提交表單,發(fā)送給 xxx.com 下的那個存在 CSRF 漏洞的web 應(yīng)用,所以用戶的信息,就被迫修改了。
解決方案
CSRF 防御的原理是,在用戶登錄的時候,生成一個隨機的 token,將它存儲在 cookie中(默認(rèn)情況,也可以放在 session 中),在生成表單時,生成一個隱藏域,隱藏域的值就等
于 token 的值。如果用戶提交這個表單,就可以在接收用戶請求的 web 應(yīng)用中,判斷隱藏域的 TOKEN 值是否和用戶 COOKIE 中的 TOKEN 值一致,如果不一致或沒有這個值,就判
斷為 CSRF 攻擊。攻擊者無法預(yù)測每一個用戶登錄時生成的那個隨機 TOKEN 值,所以無法偽造這個參數(shù)。
常見問題
(1) 為什么不直接驗證 referer?
因為還有站內(nèi)發(fā)出的 csrf,并且 referer 是可以被篡改的,是不可靠的數(shù)據(jù)
(2) 如果先發(fā)生 xss 攻擊,攻擊者可以拿到用戶頁面的 token 怎么辦?
無解,請先做好 xss 防范。
文件包含
php 可 能 出 現(xiàn)文 件 包 含 的 函 數(shù): include、 include_once 、 require、 require_once 、show_source、highlight_file、readfile、file_get_contents、fopen、file
防范方法:
對輸入數(shù)據(jù)進行精確匹配,比如根據(jù)變量的值確定語言 en.php、cn.php,那么這兩個文件放在同一個目錄下'language/'.$_POST[‘lang'].'.php',
那么檢查提交的數(shù)據(jù)是否是 en 或者 cn 是最嚴(yán)格的,檢查是否只包含字母也不錯,通過過濾參數(shù)中的/、..等字符。
HTTP 響應(yīng)拆分
php 中可導(dǎo)致 HTTP 響應(yīng)拆分的情況為:使用 header 函數(shù)和使用$_SERVER 變量。注意php 的高版本會禁止 HTTP 表頭中出現(xiàn)換行字符,這類可以直接跳過本測試。
防范方法:
精確匹配輸入數(shù)據(jù)
檢測輸入輸入中如果有/r 或/n,直接拒絕
變量覆蓋
php 變量覆蓋會出現(xiàn)在下面幾種情況:
遍歷初始化變量
例:
復(fù)制代碼 代碼如下:
foreach($_GET as $key => $value)
$$key = $value;
函數(shù)覆蓋變量:parse_str、mb_parse_str、import_request_variables,Register_globals=ON 時,GET 方式提交變量會直接覆蓋
防范方法:
設(shè)置 Register_globals=OFF
不要使用這些函數(shù)來獲取變量
動態(tài)函數(shù)
當(dāng)使用動態(tài)函數(shù)時,如果用戶對變量可控,則可導(dǎo)致攻擊者執(zhí)行任意函數(shù)。
例:
復(fù)制代碼 代碼如下:
<?php
$myfunc=$_GET['myfunc'];
$myfunc();
?>
防御方法:
不要這樣使用函數(shù)
會話安全
HTTPOnly 設(shè)置
session.cookie_httponly = ON 時,客戶端腳本(JavaScript 等)無法訪問該 cookie,打開該指令可以有效預(yù)防通過 XSS 攻擊劫持會話 ID
domain 設(shè)置
檢查 session.cookie_domain 是否只包含本域,如果是父域,則其他子域能夠獲取本域的cookies
path 設(shè)置
檢查 session.cookie_path,如果網(wǎng)站本身應(yīng)用在/app,則 path 必須設(shè)置為/app/,才能保證安全
cookies 持續(xù)時間
檢查 session.cookie_lifetime,如果時間設(shè)置過程過長,即使用戶關(guān)閉瀏覽器,攻擊者也會危害到帳戶安全
secure 設(shè)置
如果使用 HTTPS,那么應(yīng)該設(shè)置 session.cookie_secure=ON,確保使用 HTTPS 來傳輸cookies
session 固定
如果當(dāng)權(quán)限級別改變時(例如核實用戶名和密碼后,普通用戶提升到管理員),我們就應(yīng)該修改即將重新生成的會話 ID ,否則程序會面臨會話固定攻擊的風(fēng)險。
加密
明文存儲密碼
采用明文的形式存儲密碼會嚴(yán)重威脅到用戶、應(yīng)用程序、系統(tǒng)安全。
密碼弱加密
使用容易破解的加密算法,MD5加密已經(jīng)部分可以利用 md5破解網(wǎng)站來破解
參考方案
復(fù)制代碼 代碼如下:
md5(md5($password).$salt)
密碼存儲在攻擊者能訪問到的文件
例如:保存密碼在 txt 、ini、conf、inc、xml 等文件中,或者直接寫在 HTML 注釋中
認(rèn)證和授權(quán)
用戶認(rèn)證
檢查代碼進行用戶認(rèn)證的位置,是否能夠繞過認(rèn)證,例如:登錄代碼可能存在表單注入。
檢查登錄代碼有無使用驗證碼等,防止暴力破解的手段
函數(shù)或文件的未認(rèn)證調(diào)用
一些管理頁面是禁止普通用戶訪問的,有時開發(fā)者會忘記對這些文件進行權(quán)限驗證,導(dǎo)致漏洞發(fā)生
某些頁面使用參數(shù)調(diào)用功能,沒有經(jīng)過權(quán)限驗證,比如 index.php?action=upload
密碼硬編碼
有的程序會把數(shù)據(jù)庫鏈接賬號和密碼,直接寫到數(shù)據(jù)庫鏈接函數(shù)中。
隨機函數(shù)
rand() VS mt_rand()
rand()最大隨機數(shù)是 32767,當(dāng)使用 rand 處理 session 時,攻擊者很容易破解出session,建議使用mt_rand()。
代碼示例
復(fù)制代碼 代碼如下:
<?php
//on windows
print mt_getrandmax(); //2147483647
print getrandmax();// 32767
?>
可以看出 rand()最大的隨機數(shù)是 32767,這個很容易被我們暴力破解。
復(fù)制代碼 代碼如下:
<?php
$a= md5(rand());
for($i=0;$i<=32767;$i++){
if(md5($i) ==$a ) {
print $i."-->ok!!<br>";exit;
}else { print $i."<br>";}
}
?>
當(dāng)我們的程序使用 rand 處理 session 時,攻擊者很容易暴力破解出你的 session,但是對于 mt_rand 是很難單純的暴力的。
php技術(shù):PHP代碼審核的詳細(xì)介紹,轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。