-
Notifications
You must be signed in to change notification settings - Fork 1
/
tomcat.xml
270 lines (251 loc) · 11 KB
/
tomcat.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V5.0//EN"
"/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd" [
<!ENTITY article.author.xml SYSTEM "../common/article.author.xml">
<!ENTITY book.info.legalnotice.xml SYSTEM "../common/book.info.legalnotice.xml">
<!ENTITY book.info.abstract.xml SYSTEM "../common/book.info.abstract.xml">
]>
<article xml:base="http://netkiller.sourceforge.net/article/" xmlns="http://docbook.org/ns/docbook" xml:lang="zh-cn">
<articleinfo>
<title>Tomcat 安全配置与性能优化</title>
<subtitle>http://netkiller.github.io/journal/tomcat.html</subtitle>
&article.author.xml;
&book.info.legalnotice.xml;
<abstract>
<para>2016-3-30日更新增加Java 8 与 Tomcat 8 相关特性</para>
</abstract>
&book.info.abstract.xml;
<keywordset>
<keyword>tomcat</keyword>
<keyword>jre, jdk, server-jre</keyword>
<keyword>java</keyword>
</keywordset>
<pubdate>$Date$</pubdate>
<release>$Id$</release>
</articleinfo>
<section id="jvm">
<title>JVM</title>
<section id="jre">
<title>使用 Server JRE 替代JDK。</title>
<para>服务器上不要安装JDK,请使用 Server JRE. 服务器上根本不需要编译器,代码应该在Release服务器上完成编译打包工作。</para>
<para>理由:一旦服务器被控制,可以防止在其服务器上编译其他恶意代码并植入到你的程序中。</para>
</section>
<section id="JAVA_OPTS">
<title>JAVA_OPTS</title>
<screen><![CDATA[
export JAVA_OPTS="-server -Xms512m -Xmx4096m -XX:PermSize=64M -XX:MaxPermSize=512m"
]]></screen>
<para>-Xms 指定初始化时化的栈内存</para>
<para>-Xmx 指定最大栈内存</para>
<tip>
<para>Java 8 以后 -XX:PermSize 与 -XX:MaxPermSize 两个配置项被废弃</para>
</tip>
</section>
<section>
<title>java.security 优化</title>
<para>打开$JAVA_HOME/jre/lib/security/java.security文件,找到下面的内容:</para>
<screen><![CDATA[
securerandom.source=file:/dev/urandom
替换成
securerandom.source=file:/dev/./urandom
]]></screen>
</section>
</section>
<section id="tomcat">
<title>Tomcat 优化</title>
<section id="maxThreads">
<title>maxThreads 连接数限制</title>
<para>maxThreads 是 Tomcat 所能接受最大连接数。一般设置不要超过8000以上,如果你的网站访问量非常大可能使用运行多个Tomcat实例的方法。</para>
<para>即,在一个服务器上启动多个tomcat然后做负载均衡处理。</para>
<screen>
<![CDATA[
<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" />
]]>
</screen>
<tip>
<para>很多做过php运维的朋友在这里会犯一个大错误,php优化服务器通常怎做法是安装cpu以及内存的情况配置连接数,连接数过万都很正常,但java不同jvm配置要非常小心,稍有差错就会崩溃。</para>
</tip>
<para>maxThreads 配置要结合 JVM -Xmx 参数调整,也就是要考虑内存开销。</para>
<screen><![CDATA[
maxThreads 客户请求最大线程数
minSpareThreads 初始化时创建的 socket 线程数
maxSpareThreads 连接器的最大空闲 socket 线程数
]]></screen>
</section>
<section>
<title>虚拟主机</title>
<para>不要使用Tomcat的虚拟主机,每个站点一个实例。即,启动多个tomcat.</para>
<para>这也是PHP运维在这里常犯的错误,PHP的做法是一个Web下面放置多个虚拟主机,而不是每个主机启动一个web服务器。Tomcat 是多线程,共享内存,任何一个虚拟主机中的应用出现崩溃,会影响到所有应用程序。采用多个实例方式虽然开销比较大,但保证了应用程序隔离与安全。</para>
</section>
<section id="compression">
<title>压缩传输</title>
<para>通常所说的gzip压缩,Tomcat通过在server.xml配置设置压缩的选项。</para>
<screen>
<![CDATA[
<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"/>
]]>
</screen>
<tip>
<para>压缩会增加Tomcat负担,最好采用Nginx + Tomcat 或者 Apache + Tomcat 方式,压缩交由Nginx/Apache 去做。</para>
</tip>
<screen><![CDATA[
compression 打开压缩功能
compressionMinSize 启用压缩的输出内容大小,这里面默认为2KB
compressableMimeType 压缩类型
]]></screen>
</section>
</section>
<section>
<title>Tomcat 安全配置</title>
<section>
<title>禁用8005端口</title>
<para>telnet localhost 8005 然后输入 SHUTDOWN 就可以关闭 Tomcat,为了安全我们要禁用该功能</para>
<screen>
<![CDATA[
<Server port="-1" shutdown="SHUTDOWN">
]]>
</screen>
</section>
<section>
<title>安装后初始化配置</title>
<para>当Tomcat完成安装后你首先要做的事情如下:</para>
<para>首次安装完成后立即删除webapps下面的所有代码</para>
<screen><![CDATA[
rm -rf /srv/apache-tomcat/webapps/*
]]></screen>
<para>注释或删除 tomcat-users.xml 所有用户权限,看上去如下: </para>
<screen>
<![CDATA[
# cat conf/tomcat-users.xml
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users>
</tomcat-users>
]]>
</screen>
<section>
<title>隐藏版本信息</title>
<para>隐藏Tomcat版本信息,首先隐藏HTTP头中的版本信息</para>
<screen>
<![CDATA[
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
]]>
</screen>
<para>服务器信息已经被改为 Server: Neo App Srv 1.0</para>
<note>
<title>注意:当出现 404 页面时仍可能看到Tomcat的版本信息</title>
<screen><![CDATA[
HTTP Status 404 - /sdf
type Status report
message /sdf
description The requested resource is not available.
Apache Tomcat/8.0.32
]]></screen>
<para>隐藏Tomcat 404页面版本信息的方法如下</para>
<screen>
<![CDATA[
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
]]>
</screen>
<para>测试</para>
<screen><![CDATA[
HTTP Status 404 - /sdf
type Status report
message /sdf
description The requested resource is not available.
Apache
]]></screen>
</note>
</section>
<section>
<title>应用程序安全</title>
<para>关闭war自动部署 unpackWARs="false" autoDeploy="false"。防止被植入木马等恶意程序</para>
<para>关闭 reloadable="false" 也用于防止被植入木马</para>
</section>
<section>
<title>JSESSIONID</title>
<para>修改 Cookie 变量 JSESSIONID, 这个cookie 是用于维持Session关系。建议你改为PHPSESSID。 </para>
<screen>
<![CDATA[
<Context path="" docBase="path/to/your" reloadable="false" sessionCookiePath="/" sessionCookieName="PHPSESSID">
]]>
</screen>
</section>
</section>
<section>
<title>启动用户与端口</title>
<para>不要使用root用户启动tomcat,Java程序与C程序不同。nginx,httpd 使用root用户启动守护80端口,子进程/线程会通过setuid(),setgid()两个函数切换到普通用户。即父进程所有者是root用户,子进程与多线程所有者是一个非root用户,这个用户没有shell,无法通过ssh与控制台登陆系统,Java 的JVM 是与系统无关的,是建立在OS之上的,你使用什么用户启动Tomcat,那麽Tomcat 就会继承该所有者的权限。</para>
<para>这造成了一个问题,Linux系统小于1024的端口只有root可以使用,这也是为什么Tomcat默认端口是8080。如果你想使用80端口只能使用root启动Tomcat。这有带来了很多安全问题。</para>
<para>解决方案是创建一个普通用户,如:</para>
<screen><![CDATA[
groupadd -g 80 daemon
adduser -o --home /daemon --shell /sbin/nologin --uid 80 --gid 80 -c "Web Server" daemon
]]></screen>
<para>注意 /sbin/nologin , 意味着该用户不能登录,同时我也没有给它指定密码,这个用户只能用于启动tomcat,没有Shell权限就以为只被注入后无法运行linux命令。</para>
<screen><![CDATA[
chown daemon:daemon -R /srv/*
su - daemon -c "/srv/apache-tomcat/bin/startup.sh"
]]></screen>
<para>接下来解决80端口问题, 思路就是80去调用8080,或者映射端口。</para>
<para>下面是影射方案,80 跳转 8080</para>
<screen><![CDATA[
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
]]></screen>
<para>另一个就是从80请求去调用8080的方案</para>
<para>这个方案可以在 Tomcat 前段增加反向代理,例如:Nginx,Apache,Squid,Varnish或者F5, Array这类设备等等</para>
</section>
</section>
<section>
<title>如何部署应用程序</title>
<para>应用程序部署与tomcat启动,不能使用同一个用户。</para>
<para>我的tomcat 安装在 /srv目录下,Tomcat启动用户为daemon; 应用程序放在/www目录下www所有者是www用户。这样的目的是一旦tomcat被植入web shell程序,它将不能创建或编辑/www目录下面的任何内容。</para>
<screen><![CDATA[
adduser --home /www -c "Web Application" www
]]></screen>
<para>我的Tomcat安装在/srv目录下,但应用程序放在/www目录下,一般是这样的结构。</para>
<screen><![CDATA[
/www/example.com/www.example.com
]]></screen>
<para>每次升级将压错包解压到 /www/example.com/目录下,www.example.com 是符号连接,连接到刚刚解压的目录。</para>
<para>这个可以实现通过符号连接在多个版本之间快速切换。</para>
</section>
<section>
<title>延伸阅读</title>
<para>
<ulink url="http://www.netkiller.cn/www/tomcat/">《Netkiller Web 手札》 之 Tomcat 篇</ulink>
</para>
</section>
</article>