用PHP 4 2書寫安全的指令碼

2022-04-02 02:12:13 字數 3815 閱讀 7463

在很長一段時間內,php作為伺服器端指令碼語言的最大賣點之一就是會為從表單提交的值自動建立乙個全域性變數。在php4.1中,php的製作者們推薦了乙個訪問提交資料的替代手段。在php4.2中,他們取消了那種老的做法!正如我將在這篇文章中解釋的那樣,作出這樣的變化的目的是出於安全性的考慮。我們將研究php在處理表單提交及其它資料時的新的做法,並說明為什麼這樣做會提高**的安全性。

這裡有什麼錯誤?

看看下面的這段php指令碼,它用來在輸入的使用者名稱及口令正確時授權訪問乙個web頁面:

//檢查使用者名稱及口令

if($username=='kevin'and$password=='secret')

$authorized=true;

?>

pleaseenteryourusernameandpassword:

"method="post">

username:

password:

ok,我相信大約半數的讀者會不屑的說「太愚蠢了--我不會犯這樣的錯誤的!」但是我保證有很多的讀者會想「嗨,沒什麼問題啊,我也會這麼寫的!」當然還會有少數人會對這個問題感到困惑(「什麼是php?」)。php被設計為乙個「好的而且容易的」指令碼語言,初學者可以在很短的時間內學會使用它;它也應該能夠避免初學者犯上面的錯誤。

再回到剛才的問題,上面的**中存在的問題是你可以很容易地獲得訪問的權力,而不需要提供正確的使用者名稱和口令。只在要你的瀏覽器的位址列的最後新增?authorized=1。因為php會自動地為每乙個提交的值建立乙個變數--不論是來自動乙個提交的表單、url查詢字串還是乙個cookie--這會將$authorized設定為1,這樣乙個未授權的使用者也可以突破安全限制。

那麼,怎麼簡單地解決這個問題呢?只要在程式的開頭將$authorized預設設定為false。這個問題就不存在了!$authorized是乙個完全在程式**中建立的變數;但是為什麼開發者得為每乙個惡意的使用者提交的變數擔心呢?

php4.2作了什麼改變?

在php4.2中,新安裝的php中的register_globals選項預設為關閉,因此egpcs值(egpcs是environment、get、post、cookies、server的縮寫--這是php中外部變數**的全部範圍)不會被作為全域性變數來建立。當然,這個選項還可以通過手工來開啟,但是php的開發者推薦你將其關閉。要貫徹他們的意圖,你需要使用其它的方法來獲取這些值。

從php4.1開始,egpcs值就可以從一組指定的陣列中獲得:

$_env--包含系統環境變數

$_get--包含查詢字串中的變數,以及提交方法為get的表單中的變數

$_post--包含提交方式為post的表單中的變數

$_cookie--包含所有cookie變數

$_server--包含伺服器變數,例如http_user_agent

$_request--包含$_get、$_post和$_cookie的全部內容

$_session--包含所有已註冊的session變數

在php4.1之前,當開發者關閉register_globals選項(這也被考慮為提高php效能的一種方法)後,必須使用諸如$http_get_vars這樣的令人討厭的名字來獲取這些變數。這些新的變數名不僅僅短,而且它們還有其他優點。

首先,讓我們在php4.2中(也就是說關閉register_globals選項)重寫上面提到的**:

$username=$_request['username'];

$password=$_request['password'];

//檢查使用者名稱和口令

if($username=='kevin'and$password=='secret')

$authorized=true;

?>

pleaseenteryourusernameandpassword:

"method="post">

username:

password:

正如你看到的,我所需要做的只是在**的開始增加下面兩行:

$username=$_request['username'];

$password=$_request['password'];

因為我們希望使用者名稱和密碼是由使用者提交的,所以我們從$_request陣列中獲取這些值。使用這個陣列使得使用者可以自由選擇傳遞方式:通過url查詢字串(例如允許使用者建立書籤時自動輸入他們的證書)、通過乙個提交的表單或者是通過乙個cookie。如果你想要限制只能通過表單提交證書(更精確地說,是通過httppost請求),你可以使用$_post陣列:

$username=$_post['username'];

$password=$_post['password'];

除了「引入」這兩個變數以外,程式**沒有任何改變。簡單地關閉register_globals選項促使開發者更進一步了解哪些資料是來自外部的(不可信任的)資源。

請注意這裡還有乙個小問題:php中預設的error_reporting設定仍然是e_all&~e_notice,因此如果「username」和「password」這兩個值沒有被提交,試圖從$_request陣列或$_post陣列中獲得這兩個值並不會招致任何錯誤資訊。如晨不你的php程式需要嚴格的錯誤檢查,你還需要增加一些**以首先檢查這些變數。

但是這是不是意味著更多的輸入?

是的,在象上面這樣的簡單程式中,使用php4.2常常會增加輸入量。但是,還是看看光明的一面吧--你的程式終究是更安全了!

不過認真的說,php的設計者並沒有完全忽視你的痛苦。在這些新陣列中有乙個特殊的其它所php變數都不具備的特徵,它們是完全的全域性變數。這對你有什麼幫助呢?讓我們先對我們的示例進行一下擴充。

為了使得站點中的多個頁面可以使用使用者名稱/口令論證,我們將我們使用者認證程式寫到乙個include檔案(protectme.php)中:

functionauthorize_user($authuser,$authpass)

?>

現在,我們剛才的頁面看上去將是這樣的:

require('protectme.php');

authorize_user('kevin','secret');

?>

很簡單,很清晰明了,對不對?現在是考驗你的眼力和經驗的時候了--在authorize_user函式中少了什麼?

在函式中沒有申明$_post是乙個全域性變數!在php4.0中,當register_globals開啟時,你需要增加一行**以在函式中獲取$username和$password變數:

functionauthorize_user($authuser,$authpass)

?>

和剛開始的程式一樣,這個程式也存在安全漏洞,在url的最後加上?authorized=1可以繞過安全措施直接訪問頁面內容。開發者可以將$authorized視為乙個session變數而忽視了可以很容易地通過使用者輸入設定同樣的變數。

當我們增加了我們的特殊的陣列(php4.1)並關閉register_globals(php4.2)後,我們的程式將是這樣的:

session_start();

if($username=='kevin'and$password=='secret')

$_session['authorized']=true;

?>

是不是更加簡單了?你不再需要再將普通的變數註冊為乙個session變數,你只需要直接設定session變數(在$_session陣列中),然後用同樣的方法使用它。程式變得更短了,而且對於什麼變數是session變數也不會引起混亂!

總結在這篇文章中,我解釋了php指令碼語言作出改變的深層原因。在php4.1中,新增了一組特殊資料以訪問外部資料。這些陣列可以在任何範圍內呼叫,這使得外部資料的訪問更方便。在php4.2中,register_globals被預設關閉以鼓勵使用這些陣列以避免無經驗的開發者編寫出不安全的php**。

深入了解php4 2 重訪過去

所以呢,可以這樣理解 while 迴圈 它執行一系列的命令,直到乙個特定的條件滿足。但是,現在我們想一想,如果條件的第乙個重複就滿足條件了,那將會出現什麼情況呢?例如,在上面的重複中,如果你輸入2001,該迴圈將一次也不執行。你自己親手試試然後你就會明白我們的意思了。所以,如果你遇到必須至少執行一次...

php的書寫模式 PHP書寫格式詳解

摘要 從乙個例子開始。啟動編輯器,建立乙個php檔案並鍵入如下 echo 你好!將該檔案命名為 test.php 並儲存於 e html 目錄下。在瀏覽器位址列裡訪問該 php 檔案 輸出結果如下 你好!在該例子中,我們以 echo 指令輸出乙個字串 你好!從這個例子可以看出 從乙個例子開始。ech...

php格式書寫,PHP書寫格式詳解 必看

從乙個例子開始。echo 你好!將該檔案命名為 test.php 並儲存於 e html 目錄下。你好!在該例子中,我們以 echo 指令輸出乙個字串 你好!從這個例子可以看出 php 檔案或 php 段以 結束,中間為php 每乙個指令集以 符號結束 瀏覽器得到的為 php 解析器執行完 php ...