1. 程式人生 > 實用技巧 >php中的一些需要注意點

php中的一些需要注意點

PHP中的全域性變數global和GLOBALS的區別

1、global

global的作用是定義全域性變數,但是這個全域性變數不是應用於整個網站,而是應用於當前頁面,包括include或require的所有檔案。但是在函式體內定義的global變數,函式體內可以使用,在函式體外定義的global變數不能再函式體內使用。

2、$GLOBALS

$GLOBALS陣列中,每一個變數為一個元素,鍵名對應變數名,值對應變數的內容。$GLOBALS是一個超全域性變數。注意$GLOBALS的寫法,比如變數$a1,寫法為$GLOBALS['a1'].

變數覆蓋問題

register_globals

register_globals是php.ini裡的一個配置,這個配置影響到php如何接收傳遞過來的引數。
register_globals為on的時候,傳遞過來的值會被直接註冊為全域性變數直接引用,而off的時候,我們需要到特定的數組裡去得到它。
例如:
register_globals=off的時候,下一個程式接收的時候應該用$GET['user_name']和$_GET['user_pass']來接收傳遞過來的值。
register_globals=On的時候,下一個程式可以直接使用$user_name和$user_pass來接收值。

經常導致變數覆蓋漏洞的場景有:$$使用不當,extract()函式使用不當,parse_str()函式使用不當,import_request_variables()使用不當,開啟了全域性變數註冊等。

$$導致的變數覆蓋問題

$$這種寫法稱為可變變數,一個可變變數獲取了一個普通變數的值作為這個可變變數的變數名。

<?php
$a = "hello";
echo "$a"; //輸出hello
$a="world";
echo "$a"; //輸出hello
echo "$$a"; //輸出word
echo "$a ${$a}"; //輸出hello world
echo "$a $hello"; //輸出hello world
?>
漏洞產生

使用foreach來遍歷陣列中的值,然後在將獲取到的陣列鍵名作為變數,陣列中的鍵值作為變數的值,因此產生了變數覆蓋漏洞。

<?php
foreach ($_GET as $key => $value) {
${$key} = $value;
}
echo $a;
?>

get得到的資料value,關鍵第3行,用傳進來的key做為新的變數,將get傳進來的賦值給它。第行回解析為a=1。就造成了變數覆蓋。

extract()函式使用不當
1、extract()函式介紹

extract()函式從陣列中將變數匯入到當前的符號表。

該函式使用陣列鍵名作為變數名,使用陣列鍵值作為變數值。針對陣列中的每個元素,將在當前符號表中建立對應的一個變數。

該函式返回成功設定的變數數目。

2、語法

extract(array,extract_rules,prefix)

引數 描述

array必需。規定要使用的陣列

extract_rules可選。extract()函式將檢查每個鍵名是否為合法的變數名,同時也檢查和符號表中已存在的變數名是否衝突。對不合法和衝突的鍵名的處理將根據引數決定。

可能的值: EXTR_OVERWRITE - 預設。如果有衝突,則覆蓋已有的變數。 EXTR_SKIP - 如果有衝突,不覆蓋已有的變數。 EXTR_PREFIX_SAME - 如果有衝突,在變數名前加上字首 prefix。 EXTR_PREFIX_ALL - 給所有變數名加上字首 prefix。 EXTR_PREFIX_INVALID -僅在不合法或數字變數名前加上字首 prefix。 EXTR_IF_EXISTS - 僅在當前符號表中已有同名變數時,覆蓋它們的值。其它的都不處理。 EXTR_PREFIX_IF_EXISTS - 僅在當前符號表中已有同名變數時,建立附加了字首的變數名,其它的都不處理。 EXTR_REFS - 將變數作為引用提取。匯入的變數仍然引用了陣列引數的值。

prefix可選。 如果 extract_rules 引數的值是 EXTR_PREFIX_SAME、EXTR_PREFIX_ALL、 EXTR_PREFIX_INVALID 或 EXTR_PREFIX_IF_EXISTS,則 prefix 是必需的。 該引數規定了字首。字首和陣列鍵名之間會自動加上一個下劃線。

從以上說明我們可以看到第一個引數是必須的,會不會導致變數覆蓋漏洞由第二個引數決定,該函式有三種情況會覆蓋已有變數。

<?php
$a = 1; //原變數值為1
$b = array('a' => '3');
extract($b); //經過extract()函式對$b處理後
echo $a; //輸出結果為3
?>
3、漏洞重現
"extract($_GET);
if(isset($bdctf))
{
$content=trim(file_get_contents($flag));//file_get_contents—將整個檔案讀入一個字串
if($bdctf==$content) //trim—去除字串首尾處的空白字元(或者其他字元)
{ echo'bdctf{**********}'; }
else
{ echo'這不是藍盾的密碼啊'; }
}"

題目分析 題目使用了extract($_GET)接收了GET請求中的資料,並將鍵名和鍵值轉換為變數名和變數的值,然後再進行兩個if 的條件判斷,所以可以使用GET提交引數和值,利用extract()對變數進行覆蓋,從而滿足各個條件。

解題思路 if($bdctf==​$content) 輸出flag 利用extract($_GET)漏洞,使$bdctf與​$content都為空或者不存在就滿足 ​$bdctf==$content get ?flag=&bdctf= 得到flag

parse_str()函式使用不當

1、parse_str函式介紹

parse_str()函式把查詢字串解析到變數中。

註釋:如果未設定array引數,由該函式設定的變數將覆蓋已存在的同名變數。

註釋:php.ini檔案中的magic_quotes_gpc設定影響該函式的輸出。如果已啟用,那麼在parse_str()解析之前,變數會被addslashes()轉換。

parse_str函式的作用就是解析字串並註冊成變數,在註冊變數之前不會驗證當前變數是否存在,所以直接覆蓋掉已有變數

2、語法

parse_str(string,array)**

引數描述

string必需。規定要解析的字串。

array可選。規定儲存變數的陣列名稱。該引數指示變數儲存到陣列中。

import_request_variables()使用不當

1、import_request_variables()函式介紹

import_request_variables 將GET/POST/Cookie變數匯入到全域性作用域中

import_request_varibales()函式就是把GET、POST、COOKIE的引數註冊成變數,用在register_globals被禁止的時候

2、語法

bool import_request_variables(string$type,[string$prefix])

$type代表要註冊的變數,G表示GET,P表示POST,C代表COOKIE,第二個引數為字首

PHP中0、空、null和false之間的區別

原因是PHP中變數是以C語言的結構體來儲存的,空字串和NULL,false都是以值為0儲存的,其中這個結構體有個zen_uchartype;這樣的成員變數,他是用來儲存變數的型別的,而空字串的型別是string,NULL的型別是NULL, false是boolean

所以空字串'',false,NULL和0是值相同而型別不一樣

注意:NULL是一種特殊的型別,兩種情況下為NULL。

1、$var = NULL;

2、$var;

3、""、0、"0"、NULL、FALSE、array()、var $var; 以及沒有任何屬性的物件都將被認為是空的,如果var為空,則返回TRUE(這地方我是不太理解的)

$a = 0;
$b="0";
$c= '';
$d= null;
$e = false;

echo "5個變數-原始測試型別";
var_dump($a);//int 0
var_dump($b);//string '0'
var_dump($c);//string ''
var_dump($d);//null
var_dump($e);//boolean false

echo "<h4>empty測試</h4>";
var_dump(empty($a));//true
var_dump(empty($b));//true
var_dump(empty($c));//true
var_dump(empty($d));//true
var_dump(empty($e));//true

echo "<hr>";
var_dump(isset($a));//true
var_dump(isset($b));//true
var_dump(isset($c));//true
var_dump(isset($d));//【false】 見結論一
var_dump(isset($e));//true

echo "<h4>(==)雙等式測試</h4>";
var_dump($a == $b);//true
var_dump($a == $c);//true
var_dump($a == $d);//true
var_dump($a == $e);//true !!

var_dump($b == $c);//【false】見結論二
var_dump($b == $d);//【false】見結論二
var_dump($b == $e);//true

var_dump($c == $d);//true
var_dump($c == $e);//true

echo "<h4>(===)三等式測試</h4>";
var_dump($a === $b);//false
var_dump($a === $c);//false
var_dump($a === $d);//false
var_dump($a === $e);//false

var_dump($b === $c);//false
var_dump($b === $d);//false
var_dump($b === $e);//false

var_dump($c === $d);//false
var_dump($c === $e);//false

總結

對於【0;'0';'';null;false】五種型別

empty操作以上五個變數,都返回false

結論一:

關於變數型別的理解

1.null為不存在之意:php底層的zval空間裡(結構見下方)沒有存其value值,只儲存了一個type標誌其 IS_NULL(所以解釋了 empty(null)=true,isset(null)=false ,isset('')=true)

2.【0 ; '0' ; '' ; false 】:這四個為存在,php底層是開闢zval空間儲存,有value,有type.

結論二:

1、string '0'與 string '' 不相等,(想一下就明白,同類型比較【1個長度】的字串怎麼可能 等於 【0個長度】 的字串)

2、int 0 卻和 string '' 空相等,(非同類形比較,php會做型別轉換)

3、string '0'null 不相等,int 0null 相等

ereg()

ereg()函式用指定的模式搜尋一個字串中指定的字串,如果匹配成功返回true否則返回false。搜尋字母的字元是大小寫敏感的。

ereg函式存在NULL截斷漏洞,導致正則過濾被繞過,所以可以使用%00截斷正則匹配。

ereg()只能處理字串,遇到陣列做引數返回NULL,判斷用的是===,要求型別也相同,而NULL跟FALSE型別是不同的,strpos()引數同樣不能為陣列,否則返回NULL。

preg_replace()函式

preg_replace($pattern, $replacement, $subject)
函式作用:搜尋subject中匹配pattern的部分,以replacement進行替換。
$pattern:要搜尋的模式,可以是字串或一個字串陣列
$replacement:用於替換的字串或字串陣列。
$subject:要搜尋替換的目標字串或字串陣列

preg_replace函式的引數pattern輸入/e模式的時候,引數replacement的程式碼當做PHP程式碼執行。

intval()函式繞過

intval函式引數填入科學計數法的字串,會以e前面的數字作為返回值,而對於科學計數法+數字則會返回字串型別。

<?php
$num='2e4';
echo(intval($num)); //輸出2
echo('<br>');
echo(intval($num+1)); //輸出20001
?>