PHP安全編程:register_globals的安全性

來源:互聯網
上載者:User

標籤:

如果你還能記起早期Web應用開發中使用C開發CGI程式的話,一定會對繁瑣的表單處理深有體會。當PHP的register_globals配置選項開啟時,複雜的原始表單處理不複存在,公用變數會自動建立。它讓PHP編程變得容易和方便,但同時也帶來了安全隱患。

使用者輸入從何而來?第一個源是 GET、POST 和 COOKIE 資料。一般稱為 GPC 資料。此資料的可識別程式依賴於一個有爭議的 php.ini設定:register_globals。在 PHP V4.3.0 以後,register_globals 預設情況下被設定為 Off。但是幾年前,在 PHP 中,register_globals 的預設值是開啟的,所以存在很多需要它的代碼。

事實上,register_globals是無辜的,它並不會產生漏洞,同時還要開發人員犯錯才行。可是,有兩個主要原因導致了您必須在開發和布署應用時關閉register_globals:

  • 第一,它會增加安全性漏洞的數量;
  • 第二,隱藏了資料的來源,與開發人員需要隨時跟蹤資料的責任相違背。

register_globals?本身並非安全風險。但是,它為跟蹤使用者輸入和確保應用程式安全增加了難度。為什麼會這樣?因為如果開啟register_globals,在全域名稱空間和 $_GET、$_POST 或 $_COOKIE 數組中,將建立 GET、POST 和 COOKIE 傳遞到 PHP 指令碼的所有變數。

下面是工作方式及其重要性的樣本:

 1 <?php 2  3 // See if the user has the secret cookie. 4 if (!empty($_COOKIE[‘secret‘])) { 5    $authorized = true; 6 } 7  8 // Now let‘s go through a list of press releases and show them. 9 $releases = get_press_releases();10 foreach ($releases as $release) {11 12     // Some releases are restricted. Only show them to people who can13     // see secrets.14     if ($release[‘secret‘]) {15         if (!$authorized) {16             continue;17         }18     }19 20     // We must be allowed to see it.21     showRelease($release);22 }23 ?>

您應該注意幾件事。第一,依靠 cookie 來判斷使用者是否已通過身分識別驗證不是個好主意 —— 因為人們可以很容易地設定自己的 cookie 值。我們將在另外一篇文章中敘述這一點。無論如何,此指令碼的缺點在於,如果開啟 register_globals,它就不具備安全性了。

下面介紹名為 press.php 的指令碼。一般來說,當使用者訪問 press 發行版的指令碼時,其瀏覽器將顯示 http://www.example.com/company/press.php。

現在注意當使用者擅自將其更改為 http://www.example.com/company/press.php?authorized=1 時將發生什麼事?

看看前面的代碼:僅當使用者使用 cookie 時才設定 $authorized。它永遠不會被設定為假。後來引入了 register_globals —— 它取代了剛才使用的 $_GET[‘authorized‘],同時在全域範圍內還存在一個值為 1 的變數 $authorized。因此,即使使用者沒有通過 cookie 檢查,$authorized 後來在 foreach 迴圈中引用時,仍然會被驗證為真。

修複此缺陷可以使用兩種方式。其一,當然是關閉 register_globals。如果關閉它對您的生產網站沒有影響,則這是個好主意。您需要測試一下應用程式,確保它沒有因此中斷運行。

另一種方式有點像“防禦性編程”。我們只需要將 cookie 檢查更改為以下形式即可:

1 <?php2 3 // See if the user has the secret cookie.4 $authorized = false;5 if (!empty($_COOKIE[‘secret‘])) {6    $authorized = true;7 }8 ?>

這時,當使用者將 ?authorized=1 添加到指令碼 URL 時,$authorized 變數仍然被設定為 1 —— 但是它隨即會被 $authorized = false 覆蓋,只有那些實際具有秘密 cookie 的使用者才能看到受限的 press 發行版。他們仍然可以設計自己的 cookie。

審計代碼的教訓:設法關閉 register_globals。如果不開啟 register_globals 應用程式就不能運行,並且您無法修改它,或者在應用程式必須啟動並執行地方您無法控制 PHP 配置,則需要在條件塊中尋找所有全域變數設定,或者通過某些函數調用進入全域範圍。如果 register_globals 為開啟狀態,則這兩種情形都是由使用者將變數設定為任意值引起的。

找到這些變數的好辦法是將 php.ini 設定 error_reporting 設定為 E_ALL,同時使用 log_errors 或 display_errors,這樣,所有 PHP 警告和錯誤都會被分別記錄在檔案中或顯示在螢幕上。每當使用未初始化的變數(假定具有值)時,您將得到一條 E_NOTICE。這像 C 和 Java? 語言中那樣,仍然與讓 PHP 要求聲明 變數有所不同。結果,當我們的第一個版本的指令碼運行時,出現的錯誤訊息是:

1 Notice: Undefined variable: authorized in C:\var\www\articles\press.php 2 on line 15

只要使用者沒有許可權,錯誤就發生在第 15 行,而不是起初設定變數的第 5 行。PHP 在布爾上下文中將不確定的變數解釋為假(參閱 參考資料 中列出的 PHP 手冊中的“類型強制轉換”),這樣代碼無論如何都會“正常運行”了 —— 除非有人暗中使用別的方式定義 $authorized。

如果您必須要開發一個在register_globals開啟的環境中布署的應用時,很重要的一點是您必須要初始化所有變數並且把error_reporting 設為 E_ALL(或 E_ALL | E_STRICT)以對未初始設定變數進行警告。當register_globals開啟時,任何使用未初始設定變數的行為幾乎就意味著安全性漏洞。

PHP安全編程:register_globals的安全性

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.