避免十大常見網絡應用程序安全錯誤
如果測試網絡應用程序的安全問題就像寫文章那樣簡單,那么世界會變得多么美好。最近,有人要求我給出一個網絡應用程序常見安全錯誤的清單。這項工作很簡單,下面是我常見到的“陷阱(gotchas)”:
1. 盲目信任通過cookie傳遞的信息以及通過URL傳遞的參數
2. 不檢查屏幕輸入
3. 預驗證(Pre-validation)帳號
4. 無約束的用戶登錄
5. 網絡文件夾訪問權限設置錯誤
6. 緩沖敏感信息
7. 安裝Web server demo
8. 忘記修改后端數據庫的默認口令
9. 忘記安裝安全補丁
10. 開放網絡管理端口
下面是前五個常見錯誤的簡要介紹:
信任,但也要驗證
“信任,但也要驗證(Trust but verify)”是我最喜歡的座右銘之一。網絡應用程序設計師和程序員應該很好的實踐這句座右銘。盡管cookie和URL參數大大簡化了開發者的工作,但我們不應該忘記驗證它們所傳遞數據的有效性。
許多網絡商務平臺從臭名昭著的“購物車漏洞(shopping cart vulnerability)”學會了這個,網上小偷可以通過這個漏洞來修改購物車中的商品價格。而購物車本身不過是一個基于文本的cookie而已。服務器在檢驗之后,會合計保存在cookie中的條目價格。設想一下:客戶完全控制了價格,這種情況會有多可怕。更糟糕的是,服務器沒有驗證數據的手段。我敢肯定,許多網絡商務經歷了更嚴重的沖擊。
檢查這個問題的最好方法就是清除所有的cookie,運行應用程序,并看看寫到磁盤中的cookie。我總是看看cookie的內容,這樣可以避免敏感的信息(例如任務(role)甚至用戶id和口令)沒有保存到cookie中。
命令可以等同于控制
我曾經看到過這樣一個系統,它通過URL傳遞的參數來進行程序控制。當我查看它的源代碼后,我注意到了一個普通線程,系統級的命令用如下形式嵌入到URL中:“action=’do something’”。
在測試過程中,我編寫了一對自定義URL來看看系統是如何處理它們的。不出所料,通過我在URL中嵌入的命令(“action=’cat xxx>>/etc/passwd’”)我獲得了系統的控制權。
概括的說:如果你通過URL欄來傳遞參數,那么你至少應當解析它的無效內容和惡意內容。你最好對URL參數設置約束,這樣當傳遞來的參數值在意料之外時,你的程序依然可以處理它。測試你的程序是否存在這個問題也很容易——修改URL欄中的地址,然后看看你的應用程序是如何處理這個數據的。
千萬不要忘了驗證數據有效性
在測試網絡應用程序的過程中,我經常會發現不驗證輸入數據有效性的字段,它們簡直就是緩沖區溢出和SQL injection攻擊者的金礦。測試時,我會打開記事本并創建一個長度超過500的字符串,然后把它剪切拷貝到口令輸入框中。如果系統沒有限制輸入字符串的長度,那么它往往會掛起或者崩潰。
然后我將測試驗證規則,我會把一個總是等于“真”(例如“OR ‘x’=’x’”)的條件語句附加到口令輸入框中。由于通過這種方法,SQL語句已經建立,因此許多系統都會被操控,從而允許未授權的訪問——許多系統都會被這種“OR TRUE”語句所欺騙。下面是可以用來控制系統的SQL語句的例子:
Select userid, passwd from USERS where userid = :uid_entered and passwd = pwd_entered
假設用戶在useid字段中鍵入“admin”,在口令欄中鍵入“OR ‘x’=’x’”,那么這個SQL語句就會解釋為“select userid, passwd from USERS where userid=admin and passwd=password OR 'x'='x'”,設計者可能會沒有預料到這種情況的出現。
歡迎毯下的鑰匙
另一個常見的錯誤就是把系統帳號作為應用程序數據庫的預驗證帳號,我常常對這中錯誤出現的頻率之高感到吃驚。許多網絡應用程序把用戶憑證(也就是用戶名和口令)保存到自己的數據庫中。在驗證用戶憑證的有效性之前,你必須登錄到數據庫,因此,系統一般用一種我稱之為“預驗證登錄帳號”的方法來處理驗證;例如,當以“admin/admin”登錄系統時,就會驗證屏幕輸入與數據庫中保存的用戶名和口令是否相匹配。
#p#值得注意的是,我發現每個預驗證登錄帳號總是管理員類型的帳號,這些帳號具有最大權限。使得情況更具有風險性的是:為了讓網絡應用程序可以訪問帳號和口令,數據庫一般保存到Webroot目錄中或者起始頁(start page)下的目錄中。無論是上述兩種情況下的哪一種,惡意用戶都能很容易獲得口令。這種情況非常像把房門鑰匙藏在歡迎毯下,或者把備用的車鑰匙放在汽車的遮陽板上。這個錯誤很嚴重,它的存在有利于惡意用戶闖入網絡程序。
右拐還是左拐
我還喜歡做這樣一種測試:以管理員的身份合法登錄,打開任何管理頁面(例如,“添加新用戶頁”),然后注銷登錄。當會話終止(通過打開一個瀏覽器來確認)后,點擊這個書簽。令人吃驚的是,應用程序往往自動授以我管理員權限。
另一個技術就是查看以及被注釋掉但還沒有從基線(baseline)中刪除的死代碼。在這種情況下,我會以客戶(或者任何權力有限的用戶)身份登錄,并嘗試瀏覽死代碼。重復一次,許多死代碼依然保存在基線中。
開發者常常會在開發階段建立一個起始頁面(這個頁面不會被配置)——它略去了登錄過程并建立起一個測試環境。在發布系統的時候,網絡程序員一般會把注釋掉這個初始調用,或者把這個測試頁面重命名后依然把它留在Webroot目錄下。
我會檢查這些代碼來判定是否存在多個登錄也就是啟動頁面,并看看其中是否有一個可以讓我以管理員身份訪問系統而無需提供任何憑證。我還會嘗試在controls外圍登錄,特別是在開發者提供導航指南的情況下。如果不清除Internet臨時文件的話,它們就提供了有用信息。如果應用程序清楚的希望我往右走,我就試著往左走,看看它是否有防止用戶背道而馳的機制。
權限設置
總的來說,開發者不需要為訪問權限設置錯誤負責——除非應用程序構建在訪問權限基礎上。例如,如果一個網絡應用程序要求有一個可以進行全局可寫的特定的目錄(更糟糕的情況是這個目錄的權限設置為所有人都是可讀、可寫和可執行),這樣應用程序提供一個極好的可以隱藏(也有可能是觸發)惡意邏輯的場所。
許多應用程序都有存儲臨時報告的目錄。我常常會修改URL來瀏覽該目錄,這樣我就知道了該目錄的權限設置。如果應用程序提供了ad hoc查詢功能(為了存儲查詢結果,這些目錄一般是全局可寫的),我就會嘗試傳送一個可執行文件到該目錄,然后通過瀏覽器來調用它,看看它是否執行。
如果應用程序提供了任何上載功能,我就會檢查執行權限。應該很少人有網絡目錄下文件的執行權限;用戶也不應該獲得服務器上可運行程序的執行權限。如果我能在應用程序外shell(這種情況常常發生),那么任何產生的過程都屬于某個優先帳號(例如“oracle”、“root”或者“system”)并擁有它所屬帳號的權限。如應用程序應當適當控制對上載數據的訪問,否則就會潛在產生問題。另一個常見錯誤就是對上載目錄的權限設置太弱。
避免漏洞
盡管我列舉的清單沒有包含所有情況,但它包含開發者在構建基于網絡的應用程序的過程中的常見錯誤。網絡上有許多非常棒的資源,開發者和測試者可以從中獲得關于常見漏洞的更多信息。我強烈建議所有的開發者都閱讀OWASP2004報告。你也應該讀讀SANS的TOP20列表。盡管它并沒有針對網絡應用,但它會教給開發者防范漏洞的意識。在這些知識的武裝下,你應該能夠避免絕大部分常見的陷阱。
【編輯推薦】