Tomcat的系統安全管理

sea-boat發表於2014-10-20

Tomcat是一個Web容器,我們開發的Web專案執行在Tomcat平臺,這就好比將一個應用嵌入到一個平臺上面執行,要使嵌入的程式能正常執行,首先平臺要能安全正常執行。並且要最大程度做到平臺不受嵌入的應用程式影響,兩者在一定程度上達到隔離的效果。Tomcat與Web專案也是要最大程度隔離,使Tomcat平臺足夠安全。
我們先看看Tomcat可能存在哪些安全威脅。
(1) 在web應用的jsp頁面或Servlet中使用System.exit(1);
假如你是一個老闆,但是平時對待員工苛刻,工資又老是不準時發,承諾給員工的福利又做不到,所有員工敢怒不敢言,在背後嚴重鄙視你。小明實在看不下去準備離職了,他覺得要做點事情報復下你這沒人情味的老闆,作為程式設計師的他,於是敲起了幾行程式碼作為離別禮物:
SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
Date date = sdf.parse(“2019-01-01 00:00:00”);
Date now = new Date();
if (now.after(date)){
    System.exit(1);
}
在Servlet中的這幾行程式碼,平時執行一點事情都沒有,但是他就像個定時炸彈,在小明慶祝他離職五週年時,你的公司的系統就時不時得停止服務,並且還很難找出問題的所在。
(2) 在web應用中呼叫Tomcat內部核心程式碼實現類,特別是靜態類;
Tomcat中有些程式碼是可以給外部呼叫,而有些核心程式碼為避免給Tomcat帶來威脅甚至是崩潰的危險,需要控制外部程式的訪問。
以上兩種情況,都可能在Tomcat執行時導致Tomcat罷工。針對這些情況,我們有必要使用SecurityManager來保護伺服器不受類似木馬的servlet、jsp和標籤庫等得影響,使伺服器多一層保護,能執行地更加安全可靠。
    Tomcat中有一般會使用到的許可權許可有以下這些:
java.util.PropertyPermission – 控制讀/寫Java虛擬器的屬性,如java.home。
java.lang.RuntimePermission – 控制使用一些系統/執行時(System/Runtime)的功能,如exit()和exec()。它也控制包(package)的訪問/定義。
java.io.FilePermission – 控制對檔案和目錄的讀/寫/執行操作。
java.net.SocketPermission – 控制使用網路sockets連線。
java.net.NetPermission – 控制使用multicast網路連線。
java.lang.reflect.ReflectPermission – 控制使用reflection來對類進行檢視。
java.security.SecurityPermission – 控制對安全方法的訪問。
java.security.AllPermission – 給予所有訪問許可權。

毫無疑問,為了保證Tomcat的安全性,Tomcat啟動時也開啟了安全管理器,它採用的是預設的安全管理器——SecurityManager。在Tomcat啟動的批處理檔案中能找到-Djava.security.manager -Djava.security.policy==%CATALINA_BASE%confcatalina.policy,但Tomcat並沒有使用預設的策略檔案,而是指定一個catalina.policy作為策略檔案。下面列出Catalina.policy檔案有代表性的授權語句:
grant codeBase “file:${java.home}/lib/-” {
    permission java.security.AllPermission;
};
grant codeBase “file:${catalina.home}/bin/tomcat-juli.jar” {
permission java.io.FilePermission “${catalina.base}${file.separator}logs”, “read, write”;
    permission java.lang.RuntimePermission “shutdownHooks”;
    permission java.util.PropertyPermission “catalina.base”, “read”;
};
grant {
    permission java.lang.RuntimePermission “accessClassInPackage.org.apache.tomcat”;
};
上面有三個grant語句,第一個授權表示的意義比較簡單,java安裝路徑下的lib目錄及其子目錄下的jar包擁有所有的許可權。符號說明:*表示所有檔案,-表示所有檔案及其子目錄下的檔案。第二個grant是對Tomcat安裝路徑下bin目錄的tomcat-juli.jar包進行授權,包括對tomcat安裝目錄下logs目錄的讀寫許可權、關閉鉤子許可權、catalina.base系統變數的讀取許可權。第三個grant表示授權對org.apache.tomcat包裡面的類訪問許可權。
針對accessClassInPackage許可權有必要展開詳細講解,還有一個類似的許可權defineClassInPackage,由於預設的情況下是所有包都是可以被訪問呼叫的,如果要對一些包進行訪問控制,可通過以下幾個步驟使應用具備這兩種許可權的安全檢查。
首先,設定安全屬性,告訴安全管理器哪些包需要進行訪問許可權檢查,Security.setProperty
(“package.definition”,”需要檢查的包,多個包用逗號分隔”)、Security.setProperty(“package.access”, “需要檢查的包,多個包用逗號分隔”)。
其次,配置策略檔案policy,對指定類或包配置訪問指定包的許可權,例如
grant codeBase “file:${catalina.home}/webapps/manager/-“{
permission java.lang.RuntimePermission”accessClassInPackage.org.apache.tomcat”;
};
指定${catalina.home}/webapps/manager/目錄及其子目錄下得檔案都有訪問org.apache.tomcat包的許可權。格式是”accessClassInPackage.包路徑”。
最後,如果你想檢查此類是否有某個包的訪問許可權,可以顯式地使用System.getSecurityManager(). checkPackageAccess(“包路徑”);否則會在類載入器載入某個類時由loadClass方法觸發許可權檢查。如果沒許可權則丟擲SecurityException異常。
package.definition跟package.access這兩種許可權都是對包進行保護,從整體上保護一個包以避免不可信任程式碼的訪問。其一,如果不可信任程式碼想要訪問類的包保護成員,可能通過在被攻擊的包內定義自己的新類用以獲取這些成員的訪問權的方式,這種方式叫包注入。針對包注入可以向package.definition屬性新增需要保護的包,當檢測到程式碼試圖在包內定義新類時,類裝載器的defineClass方法會丟擲異常,以此達到防止包被惡意注入。可通過將包配置為RuntimePermission(“defineClassInPackage.”+package)給予許可權。其二,為防止不可信程式碼對包進行訪問,可通過限制包訪問但同時賦予特定程式碼的訪問許可權,向package.access屬性新增需要保護的包,當檢測到程式碼試圖訪問上述包中的類時,類載入器的loadClass方法會丟擲異常,以此達到包的訪問限制。把RuntimePermission(“accessClassInPackage.”+package)許可權賦予某個包即可實現其訪問許可權。
類裝載器中的defineClass跟loadClass這兩個方法比較奇特,如果想要深入瞭解可以研究JDK的類載入器的載入機制,從本書第二部分關於類載入器中知道,簡單地說,每個類被載入器載入時都會呼叫loadClass方法,loadClass會進行如下判斷:①從記憶體中查詢此類是否已經載入,如已載入直接返回此類。②如果存在父類載入器,就委派給父類載入器載入。③如果不存在父類載入器,就嘗試由啟動類載入器載入。④如果以上三種方法都無法載入此類,才呼叫這個載入器類的findClass方法,此方法再呼叫defineClass方法。
在Tomcat啟動過程中,當例項化Catalina類的時候(建構函式),就完成了package.definition跟package.access的安全屬性設定,圖3-1-5-3為SecurityConfig類圖,此類通過讀取catalina.properties中的屬性完成設定,其中兩個屬性為
package.access
=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.
package.definition
=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.
即以上這些包都需要進行許可權檢查。此類設定屬性時並非直接設定,而是先讀取系統已有的安全屬性的值,然後再把這些包追加到後面。例如,先String access = Security.getProperty(“package.access”);
再Security.setProperty(“package.access”,access+”,”+”sun.,org.apache.catalina,…”);
 

在Tomcat中,當啟動了SecurityManager進行安全管理時,有些類是必須要使用的類,為避免由安全管理器導致執行到一半拋AccessControlException異常,在啟動一開始就預先載入一些類,以此檢查是否存在某些類讀取的許可權問題。SecurityClassLoad類負責對一些類進行預載入。

點選訂購作者《Tomcat核心設計剖析》


相關文章