Tomcat 安全配置與性能優化

http://netkiller.github.io/journal/tomcat.html

Mr. Neo Chen (陳景峯), netkiller, BG7NYT


中國廣東省深圳市龍華新區民治街道溪山美地
518131
+86 13113668890


版權聲明

轉載請與作者聯繫,轉載時請務必標明文章原始出處和作者信息及本聲明。

文檔出處:
http://netkiller.github.io
http://netkiller.sourceforge.net

微信掃瞄二維碼進入 Netkiller 微信訂閲號

QQ群:128659835 請註明“讀者”

2017-06-16

摘要

2016-3-30日更新增加Java 8 與 Tomcat 8 相關特性


目錄

1. JVM

1.1. 使用 Server JRE 替代JDK。

伺服器上不要安裝JDK,請使用 Server JRE. 伺服器上根本不需要編譯器,代碼應該在Release伺服器上完成編譯打包工作。

理由:一旦伺服器被控制,可以防止在其伺服器上編譯其他惡意代碼並植入到你的程序中。

1.2. JAVA_OPTS

export JAVA_OPTS="-server -Xms512m -Xmx4096m  -XX:PermSize=64M -XX:MaxPermSize=512m"
			

-Xms 指定初始化時化的棧內存

-Xmx 指定最大棧內存

提示

Java 8 以後 -XX:PermSize 與 -XX:MaxPermSize 兩個配置項被廢棄

1.3. java.security 優化

打開$JAVA_HOME/jre/lib/security/java.security檔案,找到下面的內容:

securerandom.source=file:/dev/urandom
替換成  
securerandom.source=file:/dev/./urandom			
			

2. Tomcat 優化

2.1. maxThreads 連接數限制

maxThreads 是 Tomcat 所能接受最大連接數。一般設置不要超過8000以上,如果你的網站訪問量非常大可能使用運行多個Tomcat實例的方法。

即,在一個伺服器上啟動多個tomcat然後做負載均衡處理。

			
<Connector port="8080" address="localhost"
	maxThreads="2048" maxHttpHeaderSize="8192"
	emptySessionPath="true" protocol="HTTP/1.1"
	enableLookups="false" redirectPort="8181" acceptCount="100"
	connectionTimeout="20000" disableUploadTimeout="true" />

			
			

提示

很多做過php運維的朋友在這裡會犯一個大錯誤,php優化伺服器通常怎做法是安裝cpu以及內存的情況配置連接數,連接數過萬都很正常,但java不同jvm配置要非常小心,稍有差錯就會崩潰。

maxThreads 配置要結合 JVM -Xmx 參數調整,也就是要考慮內存開銷。

maxThreads  		客戶請求最大綫程數
minSpareThreads    	初始化時創建的 socket 綫程數
maxSpareThreads   	連接器的最大空閒 socket 綫程數
			

2.2. 虛擬主機

不要使用Tomcat的虛擬主機,每個站點一個實例。即,啟動多個tomcat.

這也是PHP運維在這裡常犯的錯誤,PHP的做法是一個Web下面放置多個虛擬主機,而不是每個主機啟動一個web伺服器。Tomcat 是多綫程,共享內存,任何一個虛擬主機中的應用出現崩潰,會影響到所有應用程序。採用多個實例方式雖然開銷比較大,但保證了應用程序隔離與安全。

2.3. 壓縮傳輸

通常所說的gzip壓縮,Tomcat通過在server.xml配置設置壓縮的選項。

			
<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
               compression="on"
               compressionMinSize1="2048"
               noCompressionUserAgents="gozilla, traviata"
               compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,,application/octet-stream"/>
			
			

提示

壓縮會增加Tomcat負擔,最好採用Nginx + Tomcat 或者 Apache + Tomcat 方式,壓縮交由Nginx/Apache 去做。

compression 			打開壓縮功能   
compressionMinSize   	啟用壓縮的輸出內容大小,這裡面預設為2KB
compressableMimeType 	壓縮類型			
			

3. Tomcat 安全配置

3.1. 禁用8005連接埠

telnet localhost 8005 然後輸入 SHUTDOWN 就可以關閉 Tomcat,為了安全我們要禁用該功能

			
<Server port="-1" shutdown="SHUTDOWN">
			
			

3.2. 安裝後初始化配置

當Tomcat完成安裝後你首先要做的事情如下:

首次安裝完成後立即刪除webapps下面的所有代碼

rm -rf /srv/apache-tomcat/webapps/*
			

註釋或刪除 tomcat-users.xml 所有用戶權限,看上去如下:

			
# cat conf/tomcat-users.xml
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
</tomcat-users>
			
			

3.2.1. 隱藏版本信息

隱藏Tomcat版本信息,首先隱藏HTTP頭中的版本信息

				
vim $CATALINA_HOME/conf/server.xml

    <Connector port="80" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
				maxThreads="8192"
				minSpareThreads="64"
				maxSpareThreads="128"
				acceptCount="128"
				enableLookups="false"
                server="Neo App Srv 1.0"/>

# curl -I http://localhost:8080/
HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Date: Thu, 20 Oct 2011 09:51:55 GMT
Connection: close
Server: Neo App Srv 1.0
				
				

伺服器信息已經被改為 Server: Neo App Srv 1.0

注意:當出現 404 頁面時仍可能看到Tomcat的版本信息

HTTP Status 404 - /sdf

type Status report

message /sdf

description The requested resource is not available.

Apache Tomcat/8.0.32					
					

隱藏Tomcat 404頁面版本信息的方法如下

					
mkdir -p apache-tomcat-8.0.33/lib/org/apache/catalina/util

cat >> apache-tomcat-8.0.33/lib/org/apache/catalina/util/ServerInfo.properties <<EOF
server.info=Apache
server.number=
server.built=
EOF
					
					

測試

HTTP Status 404 - /sdf

type Status report

message /sdf

description The requested resource is not available.

Apache
					

3.2.2. 應用程序安全

關閉war自動部署 unpackWARs="false" autoDeploy="false"。防止被植入木馬等惡意程序

關閉 reloadable="false" 也用於防止被植入木馬

3.2.3. JSESSIONID

修改 Cookie 變數 JSESSIONID, 這個cookie 是用於維持Session關係。建議你改為PHPSESSID。

				
<Context path="" docBase="path/to/your" reloadable="false" sessionCookiePath="/" sessionCookieName="PHPSESSID">				
				
				

3.3. 啟動用戶與連接埠

不要使用root用戶啟動tomcat,Java程序與C程序不同。nginx,httpd 使用root用戶啟動守護80連接埠,子進程/綫程會通過setuid(),setgid()兩個函數切換到普通用戶。即父進程所有者是root用戶,子進程與多綫程所有者是一個非root用戶,這個用戶沒有shell,無法通過ssh與控制台登陸系統,Java 的JVM 是與系統無關的,是建立在OS之上的,你使用什麼用戶啟動Tomcat,那麼Tomcat 就會繼承該所有者的權限。

這造成了一個問題,Linux系統小於1024的連接埠只有root可以使用,這也是為什麼Tomcat預設連接埠是8080。如果你想使用80連接埠只能使用root啟動Tomcat。這有帶來了很多安全問題。

解決方案是創建一個普通用戶,如:

groupadd -g 80 daemon
adduser -o --home /daemon --shell /sbin/nologin --uid 80 --gid 80 -c "Web Server" daemon
			

注意 /sbin/nologin , 意味着該用戶不能登錄,同時我也沒有給它指定密碼,這個用戶只能用於啟動tomcat,沒有Shell權限就以為只被注入後無法運行linux命令。

chown daemon:daemon -R /srv/*
su - daemon -c "/srv/apache-tomcat/bin/startup.sh"
			

接下來解決80連接埠問題, 思路就是80去調用8080,或者映射連接埠。

下面是影射方案,80 跳轉 8080

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

取消跳轉
iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

查看規則
iptables -t nat -L
			

另一個就是從80請求去調用8080的方案

這個方案可以在 Tomcat 前段增加反向代理,例如:Nginx,Apache,Squid,Varnish或者F5, Array這類設備等等

4. 如何部署應用程序

應用程序部署與tomcat啟動,不能使用同一個用戶。

我的tomcat 安裝在 /srv目錄下,Tomcat啟動用戶為daemon; 應用程序放在/www目錄下www所有者是www用戶。這樣的目的是一旦tomcat被植入web shell程序,它將不能創建或編輯/www目錄下面的任何內容。

adduser --home /www -c "Web Application" www
		

我的Tomcat安裝在/srv目錄下,但應用程序放在/www目錄下,一般是這樣的結構。

/www/example.com/www.example.com
		

每次升級將壓錯包解壓到 /www/example.com/目錄下,www.example.com 是符號連接,連接到剛剛解壓的目錄。

這個可以實現通過符號連接在多個版本之間快速切換。

5. 延伸閲讀

《Netkiller Web 手札》 之 Tomcat 篇