如何在Tomcat中仅允许指定域名访问?解决主机头操纵重定向漏洞
Tomcat主机头操纵重定向漏洞的内置与优化解决方案
一、Tomcat原生内置方案
1. 连接器allowedHosts属性(推荐,Tomcat 8.5+)
这是Tomcat官方提供的原生主机头白名单配置,直接在server.xml的HTTP/HTTPS连接器中设置即可:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" allowedHosts="*.example.com,localhost" />
它会直接校验请求的Host头,不符合规则的请求会被拒绝,无需自定义Valve,完全满足PCI合规的白名单要求。
2. Rewrite Valve实现灵活规则
如果需要区分HTTP/HTTPS设置不同规则(比如你当前允许所有HTTPS请求的场景),可以用Tomcat的Rewrite Valve:
- 先在
server.xml的Host节点启用该Valve:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.valves.rewrite.RewriteValve" /> </Host>
- 在项目
WEB-INF目录下创建rewrite.config,添加过滤规则:
# HTTP请求仅允许example.com子域名,HTTPS请求全部放行 RewriteCond %{HTTPS} off RewriteCond %{HTTP_HOST} !^.*\.example.com$ RewriteRule ^.*$ - [F]
这条规则会对非example.com子域名的HTTP请求返回403禁止访问,和你自定义Valve的逻辑一致,但配置更灵活,无需编译自定义类。
二、对你自定义Valve的优化点
你的HostFilterValve思路没问题,复用RequestFilterValve的匹配逻辑很高效,不过可以做两处小优化:
- 若需要支持端口校验,可以把拼接逻辑调整为
request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort(); - 可以显式支持
deny属性,让规则更灵活,比如拒绝特定恶意主机头值。
三、额外加固措施
- 强制开启HSTS:在HTTPS对应的Host节点添加
HttpHeaderSecurityValve,让浏览器强制使用HTTPS访问,从根源降低HTTP场景下的主机头风险:
<Valve className="org.apache.catalina.valves.HttpHeaderSecurityValve" hstsEnabled="true" hstsMaxAgeSeconds="31536000" />
- 确保
allowHostHeaderMismatch保持默认的false:这个属性如果开启会允许主机头与服务器名不匹配的请求,完全违背白名单的防护逻辑,必须禁用。
内容的提问来源于stack exchange,提问作者T Woods
相关产品推荐
相关产品推荐

