NO REGISTER_GLOBALS APPROVED 及 NO MAGIC_QUOTES APPROVED 計畫

register_globalsmagic_quotes 乃 PHP 中一個過時的功能,已經於 PHP 6 廢除了。仍然使用這兩個功能的程式在 PHP 6 上會出現執行問題。然而,由於 Discuz! 及部份討論區程式仍在廣泛使用 register_globalsmagic_quotes,加上其在華人社區的影響力,很多新的華人開發者跟隨 Discuz! 使用 register_globalsmagic_quotes 提供的功能,使程式在 PHP 6 不能夠執行,屆時可能是一個大災難。本計畫旨在推動停止使用 register_globalsmagic_quotes

為何拒絕使用 register_globalsmagic_quotes

register_globals

register_globals[1] 是一個 PHP 的功能,它會將 $_REQUEST 的所有鍵(Key)釋放到 Global Variable Scope,與執行 PHP 程式碼 extract($_REQUEST); 無異。register_globals 的功能會使沒有為變數進行初始化的程式帶來風險。以下是一個因為 register_globals 而帶來的風險範例,作者為 PHP 官方網站

範例
<?php
// 認證用戶,如果他是經認證的,就將 $authorized 設成正。
if(authenticate_user()) {
  $authorized = true;
}
// 如果已認證的話,就載入保密的資料。
if($authorized) {
  load_confidential_data();
}
?>

假若執行上方化碼的伺服器沒有啟用 register_globals,程式執行時並沒有安全問題,不過,當 register_globals 啟用後就出現了。由於以上程式沒有在全部情況下變數進行初始化,根據 register_globals 的特性,它會將 $_REQUEST 的值釋放至 Global Variable Scope,於是在網址列中輸入 index.php?authorized=1 便被程式誤認為已認證的。很多程式也是因為 register_globals 這些特性導致被入侵。所以使用者如非必要,也不應該開啟 register_globals,除該程式是基於 register_globalsmagic_quotes 開發,例如 Discuz!。如你是開發者,也不應該在已開啟 register_globals 的環境下開發程式。

magic_quotes

magic_quotes[2] 是一個 PHP 功能,旨在防止 SQL 入侵(SQL Injection)。magic_quotes_gpcgpc 均是分別代表 getpostcookie,即 $_GET$_POST$_COOKIE。這功能的特性是會將所 $_GET$_POST$_COOKIE 的值的所有英文單引號「'」前加上反斜「\」,變成「\'」。

然而,使用 $_GET$_POST$_COOKIE 的資訊不一定用在 SQL 中,例如寄送電郵而含有英文單引號的話,電郵中會出現大量的反斜。即使資料是寫入 SQL 中,很多程式也需要做前期處理(如在討論區發表文章需要檢查文章字數,而「'」會被當作一個字元、「\'」會被當作兩個),需要將那些反斜移除,使這功能實際毫無作用,反而使伺服器的處理速度減慢。

解決方法

register_globals

只要為所有的變數進行初始化,便能夠防止 register_globals 帶來的安全問題。將 error_reporting 的安全等級設定成 E_ALL,PHP 便會報告未初始化的變數。你可以根據這些資訊進行修改。下方將會示範如何利用上方的例子初始化變數。

範例
<?php
// 認證用戶,如果他是經認證的,就將 $authorized 設成正。
# 方法一
$authorized = false;
if(authenticate_user()) {
  $authorized = true;
}
# 方法二
if(authenticate_user()) {
  $authorized = true;
} else {
  $authorized = false;
}
# 方法三
$authorized = authenticate_user() ? true : false;
// 如果已認證的話,就載入保密的資料。
if($authorized) {
  load_confidential_data();
}
?>

另一個問題就是關閉 register_globals 後,不能使用 global variable scope 的變數,要使用超級變數(super global)才可以。假設有一個變數 $text 是從網址取得(index.php?text=1),需要改為 $_GET['text']postcookie 等也是一樣。

另一個替代方法對於基於 register_globals 編寫的程式較為方便,不過速度較慢,且 PHP 官方不建議的。在 PHP 的開頭加入一句 extract($_REQUEST); 即可。

magic_quotes

要修正的話就要將程式前期處理前的 stripslashes 移除。如果沒有前期處理的話,則在 SQL 前為變數加反斜(addslashes)。情況因認程應而變更,未能夠完整地概括。

參與

只要在你的作品中註明是參與本計畫即可。

注釋

  1. ^ PHP 官方 register_globals 介紹頁(英文)
  2. ^ PHP 官方 magic_quotes 介紹頁(英文)