設計一個表單,供使用者輸入文字並將它存檔/顯示, 是一件常做的事...
在開發 web 程式經常會需要讓使用者輸入資料, 並稍後呈現, 以下圖為例, 您先連結到 google 首頁後, 輸入 allenkuo, 並按下按鈕...
就會顯示下圖的查詢結果, 由於 google 的<form>是以 action=get 方式送出, 因此您可以在網址列看到 allenkuo 這個值。 google 在網頁的 textbox 也會顯示您剛才輸入的值, 以方便您繼續做其他的查詢
像這類允許使用者輸入, 並稍後呈現在網頁中的功能, 算是開發 web 的人經常需要寫的, 也有必要將它安全地處理, 或許您會覺得它是很簡單的功能, 但其實不少人都沒有做好哦!! 接下來我找些網頁來做說明, 為了保護及尊重別人的網站, 我會將網址及網頁內容做一點處理, 各位只需要看看各網站可能會有什麼問題即可, 萬一您看出我指的是哪些網站, 也請不要惡意去破壞對方的網站
範例1:
正常網址 :http://www..../xxx.jsp?b_c_id=54&menu_id=4, 畫面是
若手動改為http://www..../xxx.jsp?b_c_id=54&menu_id=4a, 畫面變成
原因應該是程式忘了驗證 Request "menu_id" 的值是不是數字
範例2:
正常網址 :http://www..../newsxxx.asp?EVENT_CATEGORY=活動訊息&EVENT_NAME=【活動訊息】...虛擬未來新世代...研討會!!&..., 網頁裡呈現的部份畫面是
若手動改為 http://www..../newsxxx.asp?EVENT_CATEGORY=活動訊息&EVENT_NAME=Allen最棒&..., 畫面變成
原因應該是網頁裡顯示"目前位置"的程式是直接取用 Request("Event_name") 所致, 如果網址只傳event id,再用程式去 database 擷取活動標題,就不會有這類問題
範例3:
我在此網站的網址裡, 修改了參數值, 將Edit=1改成Edit=1', 從網頁的錯誤訊息可以得知程式裡除了沒有判斷Request("Edit")是否為數值之外, 也沒有處理單引號的問題
範例4:
我在國內某知名公司的網站輸入查詢關鍵字, 且故意輸入一段 javascript code, 請參考下圖,網頁中真的會執行我輸入的 javascript code, 而網址則顯示成
http://www....com.tw/search/xx?...&keyword=%3Cscript%3Ealert%28%27a%27%29%3B%3C%2Fscript%3E&...
這也意味著我若填入惡意的 javascript code, 並將這網址寄給不知情的第三人時, 若對方只看了網域名稱並信任對方,就click這網址時, 便有可能執行我這段惡意的 javascript,當然啦,我所謂的惡意,絕對不會僅止於 say Hi 而已
![]() | ![]() |
範例5:
如果您到某網站加入會員, 多半會有"編輯個人基本資料" 的功能, 表單裡會預先填入您當初申請會員的資料, 但有些網站針對這點沒有處理得很好, 例如您在申請時填的值為
日後您要編輯個人基本資料時, 這 TextBox 裡其實不會顯示上述的值,而是顯示成
為什麼呢? 如果您此時檢視網頁原始碼, 應該可以看到類似下列的 HTML 內容
由於您當初輸入值有包含雙引號, 但日後要編輯時, 卻因為它而導致後半段的文字不見了, 如果您沒特別留意, 直接按下"儲存", 後半段的資料便真的消失了, 如果您到 google 網站測試, 如下圖所示
google 的網頁是可以正常顯示的, 這才是正確的運作過程
範例6:
我在某網路商店的查詢功能裡, 輸入
asp.net
在查詢結果頁是顯示
它算是正常運作, 但我若故意輸入
<img src="http://www.pchome.com.tw/img/pchomelogo.gif">
在查詢結果頁卻顯示
就比較不正確, 理論上應該顯示成
搜尋 : <img src="http://www.pchome.com.tw/img/pchomelogo.gif">
才比較正確 (除非當初客戶就要求這麼呈現,那就另當別論), 而這狀況如果是在 A 國家總統府網站卻顯示 B 國家的國旗時, 問題看起來就比較敏感些了
接收 QueryString 值
取值前, 要先檢查值的內容
有時參數會經由網址來傳遞, 例如您想呈現單筆的最新消息, 網址可能會設計成
http://..../news.aspx?id=99
其中的id=99, 稍後程式會去資料庫取得編號為 99 的最新消息, 並呈現在網頁中
由於使用者很容易便可以修改網址, 因此您要取得值時, 若直接寫成
int newsID = Convert.toInt32( Request["id"] );
便比較容易發生錯誤, 比較安全的做法建議是
- 檢查有沒有Request.QueryString["id"]
- 如果有, 使用 int.tryParse() 去試著將它轉型成 int 型別
- 視需要再增加其他的判斷, 例如若它代表了購買數量,就必需大於 0 或小於庫存量, 若它是news id,就不一定要限制它是否大於零
- 如果驗證不通過,就做適當的例外處理, 若傳入的值是合理的, 程式才繼續進行
由於取網址上的值是經常需要做的, 建議您將上述的動作包成一支函式, 日後需要時就呼叫它即可, 如果取值之前有先檢查, 那麼就不會發生範例 1, 3 的錯誤了。
若資料有私密性, 不宜直接信任網址上的值
若您在撰寫購物車,而目前使用者的訂單編號為199, 您可能設計成
http://..../myOrder.aspx?orderid=199
但這是有風險的,例如使用者只要將它改成
http://..../myOrder.aspx?orderid=198
就很有可能看得到其他客戶購買內容, 因此您這麼設計的時候, 必需做其他的處理, 例如查詢訂單時除了以 order id 為條件時,也要一併查目前使用者 id , 您可以寫成
string sql = "SELECT * FROM Orders WHERE UserID=" + Session["currentUserID"].ToString() + " AND OrderID=199";
如此一來, 就可以避免 A 客戶看到 B 客戶的訂單內容。
盡量不要傳遞資料庫可以取得的資訊
由於將值放在網址裡傳遞, 使用者可以輕易地修改, 因此盡量不要將值以網址傳送, 例如範例 2, 它將最新消息的標題以網址傳送, 間接地也提供別人亂改的機會, 如果網址只傳送id, 再由程式根據 id 去取得最新消息的標題, 就會比較安全些。
顯示值
這篇文章有一個假設的前提, 就是假設網站管理者是好人,他不會輸入惡意的文字來害到訪網站的使用者, 並假設可以輸入訊息的使用者, 都是可能有惡意的使用者。
若需要顯示沒有風險的值在網頁中
這算是最常見的狀況, 例如管理者在後台輸入最新消息, 並在前台顯示最新消息的內容, 由於管理者不會害人, 因此您在後台只需要在表單放 TextArea 或 HTML Editor 給管理者輸入最新消息即可(輸入內容包含文字,html tag,甚至 javascript code)。
若需要顯示有風險的值在網頁中(1)
範例 4,6, 是將使用者查詢的關鍵字顯示在網頁中, 為了避免使用者輸入 HTML tag,造成版面破壞, 或輸入惡意的 javascript code 而造成第三者受害, 因此顯示這類內容時, 最好寫成


若需要顯示有風險的值在網頁中(2)
如果您允許使用者輸入 HTML tag, 但不允許使用者輸入 javascript, 例如您正在做留言板, 它允許使用者輸入粗體字, 甚至貼圖, 那麼就無法用剛才的方法(HTMLEncode), 您可以在表單設計一個 HTML Editor , 並在使用者送出內容後,就先利用 Server.HTMLDecode 將使用者輸入內容解碼後,再檢查輸入內容裡有沒有 javascript code, iframe等, 如果有,就將它刪除,最後才存入db中, 甚至有些 HTML Editor 就內建過濾 script 的功能。
若需要顯示有風險的值在網頁中(3)
如果您允許使用者輸入 HTML tag / javascript, 並希望它們能以純文字方式呈現, 例如您正在做一個討論程式的論壇, 它允許使用者輸入程式碼(包含javascript), 您可以在表單設計一個 HTML Editor , 由於使用者在輸入程式碼或html tag時, 都會被 HTML Editor 轉換成安全的碼, 因此在呈現時就不會有問題, 您在呈現時只需要用 Server.HTMLEncode() 即可呈現於網頁中
若需要顯示部份的值在網頁中
有時您需要在網站首頁列出 3 則最新消息的標題及內容的前 100 個字, 但由於最新消息很可能是以 HTML tag 存放, 例如<b>xxxx</b>, 那麼您在擷取前100個字時,便可能會只擷取到
<b>xxxx
或
<b>xxxx<b
而導致網頁的格式被破壞, 就算很幸運地擷取到
<b>xxxx</b><img src="..." />....
那麼在網頁中呈現的也不會是100個字(因為有部份是html tag)
如果您有這個需求,可以考慮在使用者/管理者送出表單時, 就將內容由 html 轉換成純文字並存放在另一個欄位中, 稍後要取出前100個字時, 就以純文字欄位值為準, 有些 HTML Editor 俱備轉換成純文字的功能, 也有人利用 Regex 將字串刪除 html tag, 都可以做到轉換成純文字的功能
若需要顯示值在 TextBox 中
在範例 5 中, 若您需要在 TextBox 裡存放值, 在ASP.NET裡是沒問題的, 只需要寫成
txtTitle.Text = "...."; //就算有雙引號也不會有問題, 若您是寫 ASP, 則可以寫成
<input type=text value="<%=HTMLEcode( RS(...) )%>">
就可以正常地呈現雙引號了