經驗交流

更謹慎地使用外部變數

 自 PHP 4.2.0 起,為了強化系統安全,在 php.ini 裡頭的 register_globals 選項被預設為 off;如此一來,外部變數的讀取將更為嚴謹。
 在此之前,我們只要在變數名稱前方加上 $ 符號,即可取用各種外部變數的值;但現在要改用 $_xxxx['變數名稱'] 的方式才行。
 有些程式設計者貪圖一時的方便,直接將 register_globals 設為 on,以便繼續沿用「$變數名稱」的舊方法。在我看來,這可能形成系統安全的罩門所在。
 怎麼說呢?請看看以下這個例子:
 我們用一個表單來接受使用者輸入資料。
《A.htm》
......
<form action="B.php" name="DemoForm" method="POST">
<input type="file" name="UserFile">
<input type="submit" value="Send File">
</form>
......

 這個表單中的資料將被傳送給 B.php 這支程式來處理。為了安全的理由,我們在 B.php 中加入一小段的檢查程式,以確認使用者是否通過登入程序:
《B.php》
<?
session_start();

// 攔截未登入者
if ( !isset($ssnUSERNAME) ) exit;

......
?>

 這一段檢查程式有用嗎?如果程式設計者對變數命名的習慣被入侵者知悉時,他可以仿造 A.htm 的內容,寫一支足以騙過檢查程式的惡意程式,例如:
《入侵者仿製的 A.htm》
......
<form action="http://chensh.loxa.edu.tw/php/B.php" name="DemoForm" method="POST">
<input type="file" name="UserFile">
<input type="hidden" name="ssnUSERNAME" value="abc">
<input type="submit" value="Send File">
</form>
......

 B.php 對 $ssnUSERNAME 做檢查,入侵者也透過 form 送一個 $ssnUSERNAME 變數進來,那麼安全防護就破功了!
 怎麼辦呢?其實只要改用更嚴謹的方法來取得變數內容,這種入侵手法就失效了。
《更安全的 B.php》
<?
session_start();

// 攔截未登入者
if ( !isset($_SESSION['ssnUSERNAME']) ) exit;

......
?>

 所以呢?以後取得外部變數值時,還是別偷懶比較好!
2004.8.4
經驗交流