本期主題:Web 應用程式安全性基本議題
對表單值的誤解
剛開始接觸Web應用程式開發的人比較會有的誤解就是「只要對輸入表單加上限制,則使用者傳入的資料就會符合限制條件」這個錯誤。這裡以具體範例來說明:
1 <form method="post" action="form_process.php">
2 <input type="hidden" name="var_hidden" value="1" />
3 <input type="text" name="var_text" maxlength="12" />
4 <input type="checkbox" name="var_checkbox" value="請寄出資料" />
5 <input type="radio" name="var_radio" value="男" />
6 <input type="radio" name="var_radio" value="女" />
7 <select name="var_select">
8 <option value="0">橘子</option>
9 <option value="1">蘋果</option>
10<option value="2">香蕉</option>
11</select>
12<input type="submit" />
13</form> |
您是否認為這個表單的接收端form_process.php一定會收到這樣的資料:
□$_POST['var_hidden']因為是hidden屬性,所以固定收到"1"
□$_POST['var_text']因為設定maxlength="12",所以最長不會超過12位元組
□$_POST['var_checkbox']因為是checkbox,所以只可能是"請寄出資料"或空字串*01
□$_POST['var_radio']是選項只有「男」與「女」的單選radio按鈕,所以一定是這兩個值之一
□$_POST['var_select']是select清單,所以一定會是「橘子」「蘋果」「香蕉」其中之一
上面每一項都是「謊言」。尤其是第三項,更是誤解中的誤解,一般透過瀏覽器送出沒有勾選checkbox的表單時,該input項目會當作根本不存在。也就是說$_POST['var_checkbox']會是NULL,與空字串意義不同。
無論顯示怎麼樣的表單,網站訪客都可以將任意資料傳送給伺服器。傳送資料的前一個頁面是否真的有顯示出表單並不重要。
筆者強烈建議初學者一定要嘗試以telnet進行HTTP連接試試看。試過就會知道無論是POST還是COOKIE,實際上都是送出下面這樣的資料,無論是字數限制還是型別限制,在攻擊者的手上都毫無意義,只要實際操作過就能感受到。
var_hidden=(任意字串1)&var_text=(任意字串2)&var_checkbox=(任意字串3)&... |
當然,這些表單的輸入限制並不是毫無意義。為了提高易用性,這些限制是很有用的。對於乖乖輸入表單的訪客而言,與其按下submit按鈕送出以後才顯示錯誤訊息,不如一開始就把文字方塊長度限制在2還比較易懂、容易使用。
□輸入表單的限制是為了讓使用者容易操作的
□接收端對收到的資料加以限制是為了安全性
這樣明確分開思考,就容易區分該採取的策略。這樣一來,輸入表單可以交給網頁設計師負責,而程式設計師也可以專心設計資料接收端。
文件根目錄的內外部
再提一個基礎的話題,您有注意過文件根目錄嗎?
以Apache來說,就是httpd.conf裡以DocumentRoot所指定的目錄。Linux各種釋出版通常指定成/var/www/html,而共用的虛擬主機服務一般命名成/home/(使用者名稱)/public_html為主。以xampp來說,文件根目錄則是安裝目錄下的htdocs目錄。IIS預設的文件根目錄則是C:\InetPub\wwwroot目錄。
如同「根目錄」這個名稱,這是網站的最上層目錄,例如網域名稱是www.example.jp,則存取http://www.example.jp/index.php就會讀取文件根目錄下的index.php。
這裡重要的是,文件根目錄以下的檔案,沒有作特殊設定的話,都可能被外部直接存取的這個事實,因為這層意義,所以我將文件根目錄下的資料夾都叫做「公開資料夾」。
例如有個Web應用程式檔案架構如下:
<DocumentRoot>
-- index.php
-- <include>
-- common.php |
以外部存取為前提所寫的index.php,通常會做好適當的安全性防護;但讓這個檔案以include等指令去讀取的include/common.php經常是沒有防備的。
由於最近register_globals on的環境已經很少了,似乎是不至於遭遇悽慘的損害,但至少這些未預料的檔案直接被存取時,通常會輸出錯誤訊息。PHP的錯誤訊息,都寫著檔案的完整路徑,造成所謂「Path Disclosure」的漏洞,雖然不能單獨直接拿來攻擊,但路徑架構被摸清楚,有可能招致「目錄游走攻擊」之類的弊害。
最單純的錯誤,例如就有案例將存放有密碼的文字檔直接以txt副檔名存放在文件根目錄底下。或許一般的程式設計師都會覺得「這樣作太扯了」,但現實就是存在有這種Web應用程式,而且還廣為使用,很嚇人吧?
要避免預料外的檔案被直接存取,可採取以下這些對策:
□在common.php前方加上防禦程式碼
□在include目錄下面加上.htaccess設定DENY
不過,如果您自己是這個Web應用程式的開發者,應該盡量改採下面這樣的架構:
<DocumentRoot>.......................................................index.php
<include>...................................................................common.php |
只要不放在文件根目錄下,就無法經由HTTP直接存取。當然,又指定<alias>或<scriptalias>話就破功了!
檔案架構越是複雜的Web應用程式,愈不該事後才隱藏公開資料夾下的檔案,而應該在一開始設計的階段就只將供人直接存取的檔案放在公開資料夾裡才好。
......更多的內容請見《網頁程式駭客攻防實戰--以
PHP 為例》 |