PHP代碼審計(初級篇)


一、常見的PHP框架

1、zendframwork: (ZF)是Zend公司推出的一套PHP開發框架

  功能非常的強大,是一個重量級的框架,ZF 用 100%面向對象編碼實現。 ZF 的組件結構獨一無二,每個組件幾乎不依靠其他組件。這樣的松耦合結構可以讓開發者獨立使用組件。 我們常稱此為 “use-at-will”設計。

2、Yii由國人開發的重量級的框架

這個框架把代碼的可重用性發揮到極致。Yii是一個高性能的PHP5的web應用程序開發框架。通過一個簡單的命令行工具 yiic 可以快速創建一個web應用程序的代碼框架,開發者可以在生成的代碼框架基礎上添加業務邏輯,以快速完成應用程序的開發。

3、CakePHP是國外的框架

  CakePHP是一個運用了諸如ActiveRecord、Association DataMapping、Front Controller和MVC等着名設計模式的快速開發框架。
  該項目主要目標是提供一個可以讓各種層次的PHP開發人員快速地開發出健壯的Web應用,而又不失靈活性

4.Symfony,是一套國外的PHP開源框架

  簡單的模板功能symfony是一個開源的PHP Web框架。基於最佳Web開發實踐,已經有多個網站完全采用此框架開發,symfony的目的是加速Web應用的創建與維護。 它的特點如下:緩存管理 、自定義URLs、搭建了一些基礎模塊、多語言與I18N支持、采用對象模型與MVC分離、Ajax支持、適用於企業應用開發。

5、CodeIgniter(CI)輕量級框架,運行速度快

  CodeIgniter 是一個簡單快速的PHP MVC 框架。
  它為組織提供了足夠的自由支持,允許開發人員更迅速地工作。使用 CodeIgniter 時,您不必以某種方式命名數據庫表,也不必根據表命名模型。這使 CodeIgniter 成為重構遺留 PHP 應用程序的理想選擇,在此類遺留應用程序中,可能存在需要移植的所有奇怪的結構。

6、CanPHP框架是一個簡潔,實用,高效,遵循apache協議的php開源框架

  它既可以完美的支持MVC模式,又可以不受限制的支持傳統編程模式。它是一個輕量級的php框架,同時也是一個實用的php工具 包。以面向應用為主,不糾結於OOP,不糾結於MVC,不糾結於設計模式,不拘一格,力求簡單快速優質的完成項目開發,是中小型項目開發首選。

7、Laravel 是一個簡單優雅的 PHP web 開發框架

  在Laravel中已經具有了一套高級的PHP ActiveRecord實現 -- Eloquent ORM。它能方便的將“約束(constraints)”應用到關系的雙方,這樣你就具有了對數據的完全控制,而且享受到ActiveRecord的所有便利。Eloquent原生支持Fluent中查詢構造器(query-builder)的所有方法。

8、SlimFramework是一個簡單的 PHP5 框架用來創建 RESTful 的 Web 應用

  可以幫助你快速編寫簡單功能強大的 RESTful 風格的web應用程序 和APIs。Slim很簡單,可以讓新手和專業人士使用。

9、ThinkPHP是一個快速、簡單、面向對象的輕量級PHP開發框架

  遵循Apache2開源協議發布,從Struts結構移植過來並做了改進和完善,同時也借鑒了國外很多優秀的框架和模式,使用面向對象的開發結構和MVC模式,融合了Struts的思想和TagLib(標簽庫)、RoR的ORM映射和ActiveRecord模式。

10、PHPUnit是一個輕量級的PHP測試框架

  它是在PHP5下面對JUnit3系列版本的完整移植。這個工具也可以被Xdebug擴展用來生成代碼覆蓋率報告 ,並且可以與phing集成來自動測試,最后它還可以和Selenium整合來完成大型的自動化集成測試。

11、KYPHP支持多數據庫,多語言,多模版,多app,多緩存,多編碼格式,模板布局,自定義類,自動加載公共類庫

  KYPHP已應用於許多大項目中,在同一程式中可同時管理多個數據庫源,管理多個緩存,並支持復雜的目錄結構。從2.1開始kyphp又極大的增強了安全性,可有效防止sql注入,xss等常見安全問題。

12、initPHP是一款輕量級的php開發框架

  采用分層體系架構,適合大中型網站架構。提供豐富的library類庫,以及簡單的框架擴展機制,InitPHP還提供詳細的開發文檔,可以讓您在使用該框架的時候更加簡單實用。 InitPHP實現了抽象DB層、分層體系架構、緩存無縫切換機制、簡單模板機制、多模型部署機制、強大的安全體系,是快速開發php應用的利器。

13、SpeedPHP是一款全功能的國產PHP應用框架系統

  SpeedPHP框架是從實際運行的商業系統中取其精華而成的,在穩定性和運行速度上都非常出色;同時有着清晰的架構,更有利於提高團隊開發效率,教程眾多,入門容易,號稱最適合初學者的PHP框架,快速帶你進入PHP高手的行列。

二、審計思路

0x01.通讀全文

1. 函數集文件

網站目錄結構:主目錄、模塊目錄、插件目錄、上傳目錄、模版目錄、數據目錄、配置目錄

2. 配置文件

3. 安全過濾文件

公共函數文件、安全過濾文件

4. Index(入口)文件

0x02.敏感關鍵字回溯參數(常用)

優點:可以快速高效的挖掘出想要的漏洞,最常用的方法;判斷敏感觸發點的位置以及上下文,追蹤參數源頭。

缺點:覆蓋不到邏輯漏洞的挖掘;不能了解整個程序的基本框架。

0x03.查找可控變量

0x04.功能點定向審計(推薦)

針對目標網站的功能點進行有針對性的代碼審計,可以利用思維導圖捋清目標站點的大概功能點及其位置,如:

  • 程序安裝

  • 文件上傳

  • 文件管理

  • 登陸驗證

  • 備份恢復

  • 找回密碼

三、php.ini安全配置

0x01.語法

  • 大小寫敏感

  • 運算符

  • 空值的表達式

0x02.安全模式

  • 禁用函數

為了更安全的運行PHP,可以用此指令來禁止一些敏感函數的使用,當你想用本指令禁止一些危險函數時,切忌把dll()函數也加到禁止列表,攻擊者可以利用dll()函數加載自定義的php擴展來突破disable_function。

  • com組件

0x03.遠程文件

  • 是否允許包含遠程文件

該配置為On的情況下,可以直接包含遠程文件,若包含的變量為可控的情況下,可以直接控制變量來執行PHP代碼

  • 是否允許打開遠程文件

允許本地PHP文件通過調用URL重寫來打開和關閉寫權限,默認的封裝協議提供的ftp和http協議來訪問文件。

0x04.目錄權限

  • HTTP頭部版本信息

防止通過http頭部泄露的php版本信息

  • 文件上傳臨時目錄

  • 用戶可訪問目錄

能控制PHP腳本只能訪問指定的目錄,這樣能避免PHP腳本訪問。

0x05.錯誤信息

  • 內部錯誤選項

表明顯示PHP腳本的內部錯誤,網站調試的時候通常把php錯誤顯示打開,在網站發布后,建議關閉PHP的錯誤回顯。

  • 錯誤報告級別

四、審計過程中涉及的超全局變量

PHP中有9個超全局變量:

0x01.$GLOBALS

  • global

作用:定義全局變量,只應用於當前網頁(包括include和require的所有文件)而不是整個網站。

  • $GLOBALS

作用:用於在PHP腳本中的任意位置訪問全局變量(從函數或方法中均可)。

// 代碼1:
<?php
$name = 123;
function test(){
    global $name;	//實現參數傳遞
    $name = 456;
}
test();
echo $name;

// 代碼2:
<?php
$name = 123;
function test(){
    $GLOBALS['name'] = 4567;        //變量的作用域設置為全局
}
test();
echo $name;

// 代碼3:
<?php
$var1 = 1;
$var2 = 2;
function test(){
    global $var1,$var2;
    $var1 = $var2;
}
test();
echo $var1;

// 代碼4:
<?php
$var1 = 3;
$var2 = 4;
function test(){
    $GLOBALS['var1'] = $GLOBALS['var2'];	//注意這里中括號內只引用變量名,不帶$
}
test();
echo $var1;

0x02. $_POST和$_GET

  • $_POST(隱藏傳參)

$_POST向服務器傳送數據。將表單內各個字段與其內容放置在HTML HEADER內一起傳送到ACTION屬性所指的URL地址。用戶看不到這個過程。

  • $_GET(URL傳參)

$_GET從服務器上獲取數據。把參數數據隊列加到提交表單的ACTION屬性所指的URL中,值和表單內各個字段一一對應,在URL中可以看到。

0x03.$_REQUEST

php中$_REQUEST可以獲取以POST方法和GET方法提交的數據,但處理速度比較慢


盡量不要使用$_REQUEST,應該從$_GET, $_POST, $COOKIE, $_ENV, $_SERVER等變量中取出需要的值。

0x04.$_FILES

$_FILES['file']['name']        //顯示客戶端文件的原名稱
$_FILES['file']['type']        //文件的 MIME 類型,例如"image/gif"
$_FILES['file']['size']        //已上傳文件的大小,單位為字節
$_FILES['file']['tmp_name']        //儲存的臨時文件名,一般是系統默認
$_FILES['file']['error']        //該文件上傳相關的錯誤代碼

首先,先打印變量$_FILES的內容,為空

然后訪問upload.html文件,上傳文件


0x05.$_SERVER

這種超全局變量保存關於報頭、路徑和腳本位置的信息等。

0x06.$_SESSION

在Web編程中Session代表服務器與客戶端之間的“會話”,意思是服務器與客戶端在不斷的交流。
在PHP中,使用$_SESSION[]可以存儲特定用戶的Session信息。並且每個用戶的Session信息都是不同的。
當用戶請求網站中任意一個頁面時,若用戶未建立Session對象,則服務器會自動為用戶創建一個Session對象,它包含唯一的SessionID和其他Session變量,並保存在服務器內存中,不同用戶的Session對象存着各自指定的信息。

Session信息的存儲與讀取

session_start(); 	//開啟Session功能
session_id();		 //獲取用戶Session ID值,如需修改在括號中傳值即可

利用Session變量存儲信息:

$_SESSION["Session名稱"]=變量或字符串信息;

讀取Session變量信息(可賦值給一個變量或者直接輸出):

變量=$_SESSION["Session名稱"];

說明:
(1)使用Session前都需要在頁面開頭用session_start()方法開啟Session功能。
(2)session_start()函數前不能有任何代碼輸出到瀏覽器,最好加在頁面頭部,或者先用ob_start()函數打開輸出緩沖區。
(3)對於一個不存在的Session變量賦值,將自動創建該變量;給一個已經存在的Session變量賦值,將修改其中的值。
(4)如果新打開一個瀏覽器,則無法獲取之前保存的Session信息。因為新打開一個瀏覽器相當於一個新的用戶在訪問。
(5)只要創建了Session變量,該Session變量就能被網站中所有頁面訪問。
(6)最好不要把大量的信息存入Session變量中,或者創建很大Session變量。如果Session變量保存的信息太多,同時訪問網站的用戶又很多會非常占用服務器資源。
實例代碼:

//session.php
<?php
	session_start();
	$_SESSION['name']="admin";
	$_SESSION['password']=123456;
	echo "所在文件:".$_SERVER["PHP_SELF"]."<br/>";
	echo "用戶名:{$_SESSION['name']} <br/>密碼:{$_SESSION['password']}";
?>
  
//c_session.php
<?php
	session_start();
	echo "所在文件:".$_SERVER["PHP_SELF"]."<br/>";
	echo "用戶名:{$_SESSION['name']} <br/>密碼:{$_SESSION['password']}";
?>


Session的生命期

Session對象的生命期:是從用戶在Session有效期內第一次訪問網站直到不再訪問網站為止的這段時間。

設置Session有效期:

ini_set('session_save_path','/tmp/');	//設置保存路徑
ini_set('session.gc_maxlifetime',60);	//保存1分鍾
setcookie(session_name(),session_id(),time()+6,"/");	//設置會話cookie的過期時間

說明:
(1)關閉瀏覽器不會使一個Session結束,但會使這個Session永遠無法訪問。因為當用戶打開新的瀏覽器窗口又會產生一個新的Session。
(2)Session對象不是一直有效,默認有效期為24分鍾。
(3)增加Session的有效期會導致Web服務器保存用戶Session的信息的時間增長,如果訪問的用戶很多,會加重服務器負擔。
(4)不能單獨對某個用戶的Session設置有效期。

刪除和銷毀Session
刪除Session常用來實現用戶注銷的功能,使得用戶能夠安全退出網站。

session_unset();//刪除$_SESSION中所有session變量
session_destroy();//清除Session ID

說明:
(1)session_unset函數只能刪除$_SESSION[]中的所有元素,不能刪除對應的Session ID,也不能刪除保存Session ID的文件。
(2)session_destroy函數只能刪除Session ID,並銷毀Session文件,但是不能刪除$_SESSION[]中的所有元素。
(3)unset()方法也可以刪除單個Session變量。

示例:利用Session限制未登入用戶訪問

//login.php
<html>
	<head>
		<title>登入</title>
	</head>
	<body>
		<?php
			session_start();
			if(!isset($_POST["login"])){
				echo '
				<form action="#" method="post">
					<p>帳號:<input type="text" name="name"/></p>
					<p>密碼:<input type="password" name="pw"/></p>
					<p><input type="submit" name="login" value="登入"/>
				</form> ';
			}
			else{
				$name=$_POST["name"];
				$pw=$_POST["pw"];
				if($name=="admin"&&$pw==123456)
				{
					$_SESSION["name"]=$name;
					$_SESSION["pw"]=$pw;
					echo '登入成功,<a href="user.php">查看個人信息</a>';
				}
				else{
					echo '帳號或密碼錯誤!<a href="JavaScript:history.back()">返回登入</a>';
				}
			}
		?>
	</body>
</html>



//user.php
<?php
	session_start();
	if(isset($_SESSION['name'])){
		echo "帳戶信息:<br/>";
		echo "用戶名:".$_SESSION["name"]."<br/>";
		echo "密碼:".$_SESSION["pw"]."<br/>";
		echo '<a href="logout.php?action=logout">注銷</a>';
	}else{
		echo '未登入用戶不允許訪問,<a href="login.php">請登入</a>';
	}
?>
 


//logout.php
<?php
	if($_GET['action']=="logout"){
		header('Refresh:3; url="login.php"');
		session_start();
		setcookie("cookiename", NULL);
		session_unset();
		session_destroy();
		echo "三秒后返回登入頁面";
	}
?>



Cookie實際上是一個很小的文本文件,網站通過向用戶硬盤中寫入一個Cookie文件來標識用戶。當用戶下次再訪問該網站時,瀏覽器會將Cookie信息發送給網站服務器,服務器通過讀取以前寫入的Cookie文件中的信息,就能識別該用戶。

Cookie的兩種形式:
(1)會話Cookie。臨時性的,只在瀏覽器打開時存在,主要用來實現Session技術。
(2)永久Cookie。永久性的,保存在用戶硬盤上並在有效期內一直可用。

創建和修改Cookie

在PHP中,利用setcookie()函數可以創建和修改Cookie,以及設置Cookie的有效期;而使用$_COOKIE[]數組可以讀取Cookie變量的值。

setcookie(name,value[,exprie,path,domain,secure]);		//創建Cookie

參數:
name:Cookie的變量名
value:Cookie的變量值
expire:Cookie的有效期
path:Cookie的服務器路徑
domain:Cookie的有效域名
secure:是否采用HTTPS來傳輸Cookie

說明:
(1)除了name和value是必需參數外,其他參數都是可選的。
(2)沒有設置有效期的Cookie為會話Cookie。
(3)修改永久Cookie時若沒設置有效期,該Cookie將被修改為會話Cookie。
(4)在使用setcookie()函數前,不要有任何HTML內容輸出到瀏覽器,否則setcookie()創建Cookie將失敗。因為Cookie也是作為HTTP協議頭的一部分。
(5)Cookie變量的值總時字符串數據類型。

使用header設置Cookie:

header('Set-Cookie:name=value;expires=".gmstrftime("%A,%d-%b-%Y %H:%M:%S GMT",time()+10)');

刪除Cookie的方法:
(1)將Cookie的變量值設置為空,並且不設置有效期,不設置有效期將刪除Cookie文件中的Cookie變量。
(2)將Cookie的有效期設置為過去的某個時刻。
無論哪種方法,瀏覽器收到這樣的Cookie響應頭信息后,將自動刪除用戶硬盤中的Cookie文件和內存中的Cookie信息。

示例:使用setcookie()函數創建及刪除Cookie數組

//test1.php
<?php
	setcookie("user[name]","admin",time()+600);
	setcookie("user[pw]","123456",time()+600);
	setcookie("user[city]","china",time()+600);
	echo '創建Cookie信息成功,<a href="test2.php">點擊查看Cookie信息</a>';
?>
 
//test2.php
<?php
	echo "Cookie信息:<br/>";
	if(isset($_COOKIE['user'])){
		foreach($_COOKIE['user'] as $key=>$value){
			echo $key."=>".$value."<br/>";
		}
		echo '<a href="test3.php">刪除Cookie信息</a>';
	}
	else{
		var_dump($_COOKIE);
	}
?>
 
//test3.php
<?php
	setcookie('user[name]',"");
	setcookie('user[pw]',"123456",time()-1);
	setcookie('user[city]',"china",time()-1);
	echo '已清空Cooike信息,<a href="test2.php">返回查看Cookie信息</a>';
?>

注意:cookie & session的聯系與區別

聯系:

  1. session是通過cookie來工作的。

  2. session和cookie之間是通過$_COOKIE['PHPSESSID']來聯系的。

  3. 通過$_COOKIE['PHPSESSID']可以知道session的id,從而獲取到其他的信息。

區別:

  1. cookie數據存儲在瀏覽器客戶端上,session數據存放在服務器上。

  2. cookie中只能存儲ASCII字符串,並需要通過編碼方式存儲為Unicode字符或者二進制數據,而session中能夠存儲任何類型的數據,包括且不限於string,integer,list,map等。

  3. cookie不是很安全,黑客可以分析存放在本地的COOKIE並進行COOKIE欺騙,從安全性出發應當使用session。

  4. session會在一定時間內保存在服務器上。當訪問增多,會占用服務器的性能,考慮到優化服務器性能方面,應當使用COOKIE。

  5. 單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。

  6. cookie支持跨域名訪問,而session不支持。

0x08.$_ENV

  • $_ENV包含服務器端的環境變量數組,可在PHP程序的任何地方直接訪問

  • $_ENV只是被動的接受服務器端的環境變量轉換為數組元素


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM