draft document -- 2003年6月11日html
做爲一名web開發者,任什麼時候候當你構建一個Web應用時,有責任確保你的應用程序可以作什麼和什麼是應該作的:在發生錯誤的時候優雅的處理錯誤;讓用戶獲取不到他們不該該查看的數據;防止惡意用戶對應用程序進行的干擾操做。java
然而,詳細的討論如何去構建一個穩定的web應用程序是一個太過複雜的主題,這一篇短文設計的是構建基於Velocity的web應用程序常見的幾個問題。短文是從一個開發者的角度寫起的,他須要同大量的html模板開發人員和最終用戶接觸。咱們鼓勵讀者發表本身的意見,其餘問題和相關的設計建議請致信 Velocity 用戶列表,或者直接聯繫做者,Will Glass-Husain。web
Velocity 如何幫助開發者建立一個穩定的App數據庫
一般,Velocity 是一個html設計師容易學會,而且不會難用的web模板工具。這一點基於以下的幾個要素:apache
Velocity 模板語言(VTL)是簡單的。 使用幾個簡單的指令,外加應用自己定義的引用,須要學習的東西少(也不怎麼凌亂)。緩存
頁面文件中不存儲非展現用的信息。 對比JSP文件,它經常須要帶上一個頁面頭文件。若是一個不懂技術的web設計師去掉了這個頭部,那麼這個JSP頁面就不起做用了。在一個Velocity模板中這樣的頭部或者其餘技術信息是不須要的。安全
在一個web頁面中沒有Java代碼。 這樣就消除了一些共有的錯誤和混亂設計,同時讓惡意的頁面編輯者去調用沒必要要的Java代碼變得困難。服務器
一個方法的異常不會阻塞一個頁面的建立。 使用MethodExceptionEventHandler,一個方法異常能夠被獲取和記錄日誌。cookie
一個無效的引用不會阻塞一個頁面的建立。 模板指令中無效的引用一般被忽略不計。頁面中一個無效的引用將會簡單的把其引用參考字打印出來。(好比:$foo)。app
基於如上的緣由,大部分Velocity開發者將會發現:沒有什麼離奇的現象或者問題,頁面以一種直接的方式被渲染。
基於Velocity穩定和安全性的具體問題
考慮安全和穩定要素時,你須要意識到基於Velocity的web應用程序的幾個特性。
Velocity 是一個模板工具, 而不是一個框架。 它不解決任何像認證、訪問控制、會話狀態或者數據持久化這樣的問題。
VTL方法調用其實是Java的方法調用。 這意味着一個糟糕的velocity應用程序設計使得模板設計者改變系統的狀態,直接執行SQL查詢或者隨意的實例化Java類。潛在的安全威脅將在下面被詳細提到。
VTL引用具備Java類型。儘管對被模板編輯者是不可見的,每個引用仍是一個具備特定類型的Java對象。若是 $apple 是一個 integer 的 「1」, $orange是一個String 的「1」,$banana是一個 double 的 「1.0」,那麼根據VTL這些對象沒有一個是==(對等)的。典型的非技術html模板設計者可能會對此感到迷惑。(事實上,若是對象不是同一個類型的,會有對它們字符串值的比較。所以, 在VTL中, $apple和 $orange如今是對等的了。)
在構建安全,穩定的Velocity Web應用程序中的最佳實踐。
以下所列是可以幫助你構建一個穩定的Velocity Web應用程序的最佳實踐。它們包括:
在上下文環境context中審查全部沒必要要的方法。
編碼HTML特殊字符,以免交叉腳本漏洞。(cross-scripting)
使用最新且作了合適設置的app服務器。
進行適合生產中使用的Velocity配置
在上下文環境context中審查全部沒必要要的方法。
開發者放在上下文環境中的引用通常有一到兩個重要的目的。
一、提供在頁面上面顯示的動態信息(好比:當前用戶的名字)。
二、提供輔助的控制結構和信息的從新格式化(好比:格式化數字的工具)。
把存在的對象或者bean放入上下文環境這樣的作法是頗有誘惑力的。當你這樣作的時候,你必須意識到一個很重的警告。模板能夠調用對象在頁面上下文環境中可用的任何公共方法。這意味着你應該當心地,只提供能安全的被模板設計者訪問的方法。
爲了隱藏沒必要要的方法,開發者須要建立一個包裝對象。須要重點注意的是,成爲一個對象的子對象或者實現一個接口以隱藏方法作得還不夠。緣由是:
使用接口對於模板設計者訪問實現了這個接口的這個類的任何公共方法沒有施加任何影響。
當模版設計者可以使用 VTL 指令 $reference.super().badmethod() 調用一個來自父類的方法時,採用子類的方式沒有幫助。
有一些須要特別關注的事情:
不要包含那種擁有能夠改變應用狀態的任何方法的對象。那樣作的話會破壞 MVC 模式,並且很難去調試。
避免擁有能夠執行SQL查詢的方法的對象/關係型數據庫對象。Jakarta 項目 Torque 和 Turbine的用戶須要特別注意的是:生成的Torque對象包含了一個能夠訪問org.apache.Torque.util.BasePeer 類的一個實體的getPeer方法。這個類包含了許多容許隨意執行SQL查詢的方法。
永遠不要把文件和相似的對象放到上下文環境中。永遠經過封裝的對象展現文件系統信息。
編碼HTML特殊字符,以免交叉腳本漏洞。
任什麼時候候一個web應用程序要顯示以前用戶輸入的文本,都存在一個包含非法文本的風險。一般,這樣的文本可能包含將致使頁面表現超出做者預期行爲的,使用了Javascript 的 HTML 標籤。當頁面被第二我的看到的時候,這是一個問題:被包含的文本會彈開窗口;抓取cookie信息;或者攔截輸入到表單裏面的數據。正由於這是一個廣泛的web應用程序設計問題,網上纔會查到大量的有關這個潛在危險的更多信息。
解決辦法是:在屏幕上顯示它們以前,一直避免使用HTML特殊字符。至少,做以下的替換:
原文文本 替換文本
< <
> >
" "
& &
爲了更好的可讀性,也要替換這些:
原文文本 替換文本
回車符
兩個空格 一個空格跟着
有四種可能被用到的替換文本的方法
一、你能夠在處理用戶輸入時迴避掉這樣的文本,使用編碼的形式存儲它們。這對於模板設計者來講是最簡單的,可是會在當你須要在其餘場景下使用沒有迴避的文本形式時引起問題。
二、你能夠建立一個在顯示時迴避文本的工具。(例 1,以下)
三、你能夠爲上下文環境的全部文本建立一個封裝的對象,自動迴避這樣的字符串。(例 2)。
四、如 Danil Dekany 建議的那樣,Velocity 能夠包含一個新的,能夠在塊內自動迴避文本的指令#escape。
例 1:Velocity 迴避文本的工具。
$HTMLText.setText($textFromUser).Escaped
$HTMLText.setText($textFromUser).EscapedMultiLine
第一行全部的 HTML 字符都會被迴避掉, 顯示 $textFromUser 的原始文本。第二將把任何傳入的返回轉換成
表現形式。(注意:你將不會想在全部狀況下都這樣作。好比:你應該包含做爲在一個表單textarea域中Enter值的傳入返回值。
例 2:使用一個封裝的文本處理對象。
$textFromUser.Escaped
$textFromUser.EscapedMultiLine
$textFromUser.PlainText
在這個例子中, 上下文環境中的 $textFromUser 被定義成了一個擁有 Escaped,EscapedMultiLine 和 PlainText 屬性的封裝對象。第一個屬性顯示 HTML 代碼被避免的文本。第二個也編碼的傳入返回。最後一個屬性返回跟輸入時同樣的文本。若是三個屬性一個都沒有給出,默認顯示的文本應該被避免掉。
例 3:使用 #escape 指令(沒有被實現)。
#escape("html")
... Tons of HTML here...
... interpolations will be implicitly escaped
#end
使用最新且作了合適設置的app服務器。
對於任何web應用程序,確保你基於Velocity的app是運行於使用最近更新或者服務包的應用服務器上。研究研究跟安全相關的配置設置,跟蹤已經發布的漏洞。做者遇到的一些問題包括:
配置你的應用服務器,使用 -Xmx java 命令行選項使Java虛擬機容許一個足夠的最大棧空間。若是沒有這個設置,你有的應用頗有可能拋出 OutOfMemoryError 。
當使用一個web服務器和Apache Tomcat 時,你常常必須明確禁止用戶訪問 WEB-INF, META-INF,和其餘系統路徑。
上溯至版本 4.1.12 版本的 Apache Tomcat 應該欺騙性的使用 DefaultServlet 來顯示 Velocity 頁面, JSP,或者任何其餘web樹結構中的模板,它們的源代碼。
配置一個 Java Security Manager 限制文件的訪問(從web 樹和模板路徑的外部)和危險的方法,如 System.exit()和 getClassLoader 的訪問。這已經被技術性的包含在了現當前版本的Velocity中(1.3.1),沒有被徹底支持。尤爲是,一些Velocity類須要訪問Classloader,而其它應該被嚴格限制。若是你對於這些問題不是很熟悉,Velocity用戶列表也許能幫助你着手開始。
只有一個基本的準則——當心關注你的特有系統的問題。
進行適合生產中使用的Velocity配置
一個安裝在生產服務器上的web應用程序比開發環境下,一般在配置上有很大的不一樣。確保利用Velocity的擴展性的 develope-guide.html#Velocity配置Keys和Values配置選項,去建立一個穩定和專業的部署。
下面是一些建議:
建立一個 EventCartridge 和 Event Handler 去獲取方法異常。記錄異常日誌,可是運行頁面繼續進行處理。
打開Velocity頁面的緩存,除了能加速頁面渲染的處理外,這樣也避免了在必然的狀況下因爲過分的也頁面內調致使的「內存溢出」。
建立贊成的錯誤頁面,以贊成你的應用的觀感。在獲取到 ParseErrorException 和 ResourceNotFoundException 時顯示這個錯誤頁面(由 Velocity.getTemplate()拋出)。包含一個對用戶友好的錯誤消息(以Velocity引用的形式傳給頁面),而且爲 開發者和系統管理員記錄技術性的詳細日誌。
同不受信任的HTML 模板設計者一塊兒工做
(注意:下面一些特定的引用代碼是過期的。見版本1.5 WGH的增補清單 - 2005/10/7)
許多Velocity應用程序,一小組人(或者僅僅一我的)爲開發一個web應用而協同工做。這種狀況下,開發者主要關注的是爲最終用戶建立一個用戶友好的安全應用。開發者爲頁面設計提供一些簡單的技術指導,大部分有尤爲是一個VTL引用工具清單,和一些訪問web樹的CVS和FTP設置。在這個廣泛的場景中,開發者和模板編輯者都有確保讓應用安全平穩的進行工做的責任。
其餘的Veloctiy應用,一大羣模板設計者建立模板文件,也許是來自外部的開發組織。經常,這些模板設計者沒有直接訪問CVS樹或者web文件系統。而多是經過一個web管理界面上傳他們爲這個web應用上傳的模板文件。這在中狀況下,模板編輯者應該被看作是不受信任的。不論是什麼模板被上傳到了系統裏面,都須要特別關注web應用程序的集成。
然而不徹底清楚到底有多少Velocity Web 應用程序是屬於這個範疇的,做者遇到過五六個建立過這種類型應用程序的開發者。做者本身也管理這一個基於Velocity的web站點,裏面有上百個HTML模板設計者,他們擁有具備上傳模板能力的帳號。
一些在同不受信任的模板設計者一塊兒開發一個web應用程序時的注意事項:
如上所述,在上下文環境中只提供安全的引用。方法不能改變app的狀態、執行SQL查詢,或者訪問文件系統。
複審 #include 和 #parse 的潛在使用。在做者的應用程序中,模板文件盒私有的用戶數據起初被存儲在同一個資源路徑下的web樹的平行目錄中。這意味着任何模板用戶能使用來自另一個用戶的模板和數據。Serge Knystautas 提出了一個針對這個困境的可能的解決方案,它是去建立一個跟用戶相關資源加載器,加載屬於當前用戶的模板文件。另外的一個解決辦法是使用一個做者開發Velocity的包,它容許開發者經過使用事件Handler控制實際由 #include 和 #parse 返回的模板。(典型的,這將限制每一個帳戶只包含那個帳戶中的頁面)。(更新:新的事件Handler包含在源代碼樹中,發佈於 版本 1.5 - WGH中)
此外,上面關於配置一個security manager的話題在這種類型的應用中變得很重要。開發者應該意識到模板設計者具備調用 getClassLoader() 返回一個可以在默認配置中實例化任何類和調用任何方法的 ClassLoader。做者已經爲Velocity推出了一個限制這種危險能力的包。(更新:計劃於版本 1.6 - WGH 中)
明確的最安全的途徑是限制模板設計在一小組受信任的模板編輯者中。然而,在有一大羣用戶能夠上傳模板的狀況下,Velocity仍然是一個有用的工具。這種狀況下,你必須更加當心的考慮圍繞系統集成和安全衍生的問題。
鳴謝
做者很感謝velocity用戶列表中的許多爲這些相關問題提供過建議,特別是那些加入了這個 discussion thread 中的成員。
這裏是原文的地址:
http://wiki.apache.org/velocity/BuildingSecureWebApplications