Apache HTTPD/mod_proxy/Tomcat和SSL与客户端认证

5

我相信这是一个常见问题,但我找不到任何我认为与此相同的问题。

我有几个在Tomcat中运行的Web应用程序,其中一些页面(例如登录页面)受到其web.xml中机密性元素定义的SSL保护。其中一个应用程序还通过证书接受客户端身份验证。我还有一个相当广泛的基于JAAS的授权和身份验证方案,并且在各种Web应用程序之间存在各种共享代码和不同的JAAS配置等等。

我真的不想在完成以下任务时干扰其中任何内容。

我现在正在将Apache HTTPD与mod-proxy和mod-proxy-balancer插入到Tomcat前面作为负载均衡器,然后再添加更多Tomcat实例。

对于HTTPS请求,我想实现的是它们被“盲目”重定向到Tomcat而不是HTTPD成为SSL终点,即HTTPD直接将密文传递给Tomcat,以便TC可以继续执行其已经处理的登录、SSL、web.xml保密性保证,最重要的是客户端身份验证。

根据我所描述的配置,这是否可能?

我非常熟悉Web应用程序、SSL、HTTPS和Tomcat,但我对Apache HTTPD的外围范围的了解有限。

如果需要,我很高兴将其移动,但这有点像使用配置文件进行编程;)

1个回答

7
这与此问题相似,我已回答过它是不可能的:

你不能仅仅将SSL/TLS流量从Apache中转到Tomcat。要么你的SSL连接在Apache处结束,然后你应该反向代理流量到Tomcat(在这种情况下,在Httpd和Tomcat之间的SSL很少有用),要么让客户端直接连接Tomcat并让其处理SSL连接。

我承认这篇文章缺乏支持此说法的链接。我想我可能是错的(我从未见过这样的操作,但这并不严格意义上意味着它不存在...)。

正如您所知,您需要一个直接连接或完全中继的连接,用户代理和SSL终点之间(在这种情况下,您希望它是Tomcat)。这意味着Apache Httpd将无法查看URL:最多只会知道主机名(使用服务器名称指示时)。

mod_proxy文档中,唯一似乎不依赖URL的选项是AllowCONNECT,这是用于HTTPS的正向代理服务器的选项。

即使在mod_proxy_balancer的选项中,也希望在配置的某个点上提供路径。它的文档没有提到SSL/HTTPS("它为HTTP、FTP和AJP13协议提供负载平衡支持"),而mod_proxy在提到CONNECT时至少提到了SSL。

我建议有几个选项:

  • 使用基于iptables的负载均衡器,不通过Httpd直接在Tomcat中结束连接。

  • 在Httpd中结束SSL/TLS连接,并使用纯HTTP反向代理到Tomcat。

这个第二种选项需要更多的配置来处理客户端证书和Tomcat的安全限制。
如果您已经使用<transport-guarantee>CONFIDENTIAL</transport-guarantee>配置了您的Web应用程序,则需要使Tomcat标记连接为安全连接,尽管它从其普通HTTP端口接收到这些连接。对于Tomcat 5,这里有一篇文章(原文是法语,但自动翻译并不太糟糕),描述了如何实现一个阀门来设置isSecure()。(如果您不熟悉阀门,它们类似于过滤器,但在Tomcat本身内部操作,在请求传播到Web应用程序之前进行操作。它们可以在Catalina中配置)我认为从Tomcat 5.5开始,HTTP连接器secure选项正是这样做的,而不需要您自己的阀门。如果使用mod_proxy_ajpmod_jk,AJP连接器也有类似的选项。
如果使用AJP连接器,mod_proxy_ajp将转发证书链中的第一个证书,并在Tomcat中使其可用(通过正常请求属性)。您可能需要SSLOptions +ExportCertData +StdEnvVars。据我所知,mod_jk(虽然已被弃用)也可以转发客户端发送的整个证书链(使用JkOptions +ForwardSSLCertChain)。这在使用代理证书时可能是必要的(如果没有直到终端实体证书的链,则代理证书毫无意义)。
如果您想使用mod_proxy_http,一个技巧是通过HTTP头(mod_header传递证书,类似于RequestHeader set X-ClientCert %{SSL_CLIENT_CERT}s。我记不清确切的细节,但重要的是要确保清除此标头,以便它永远不会来自客户端浏览器(否则可能被伪造)。如果需要完整的链式证书,可以尝试这个Httpd补丁尝试。这种方法可能需要额外的阀门/过滤器将标头转换为javax.servlet.request.X509Certificate(通过解析PEM块)。
还有几点可能会感兴趣:
  • 如果我没记错的话,您需要明确下载 Httpd 和 配置它以使用这些文件。根据您使用的 Httpd 版本,您可能需要 重新启动它以重新加载 CRLs
  • 如果您正在使用重新协商来获取客户端证书,则据我所知,CLIENT-CERT 指令不会使 Httpd 请求客户端证书(当直接使用 JSSE 连接器时,可以通过访问 SSLSession 的阀门来完成此操作)。您可能需要在 Httpd 中配置匹配的路径以请求客户端证书。

谢谢Bruno。听起来我应该(a)像你建议的那样在HTTPD和Tomcat之间使用纯文本,以HTTPD作为客户端的SSL终点,(b)摆脱<transport-guarantee>CONFIDENTIAL</transport-guarantee>,这并不困扰我,并在代码中搜索和销毁isSecure(),以及(d)使用mod_proxy_ajp,这样证书就可以通过了,事实上我已经在做了。我可以处理配置HTTPD的HTTPS和证书等问题。 - user207421
到目前为止,我唯一看到的主要问题是客户端证书。我已经配置了Tomcat不要求它们,以避免浏览器弹出窗口,并且有一个Tomcat魔法片段,用于重新握手具有客户端证书认证的应用程序的客户端,如果它还没有该证书。如果可能的话,我必须弄清楚如何让HTTPD执行此操作,否则可能只需不将该应用程序放入集群中:反正它的流量很低。除此之外,我认为这看起来很好。 - user207421
1
你可以在全局范围内放置 SSLVerifyClient none,并在 <Location /path/...> 元素中放置 SSLVerifyClient optional/require(但路径可能需要特定于 Web 应用程序的预期)。 - Bruno
谢谢,听起来就是我需要的。Tomcat没有那种粒度,这已经给我带来了另一个问题。 - user207421
如果您想直接在Tomcat中进行操作,这篇文章可能会有所帮助。我已经很久没有这样做了,所以我记不清细节了。我记得在重负载下(实际上并不是很重,但在30秒内突然出现了大约200个请求),mod_jk+Jetty/AJP 会出现一些稳定性问题:AJP连接会突然断开,日志中没有任何信息(无论是Httpd还是Jetty)。让Jetty(即使是BIO)通过JSSE直接处理请求的结果更加稳定(当时我没有完全调查原因,您可能会得到更好的结果)。 - Bruno
是的。我已经在使用自定义的Tomcat认证器,或者甚至是Valve、JAAS等各种东西。SSLProxyVerify确实可以在服务器、虚拟主机和目录级别上指定,但我可能会直接将其传递给相关的Web应用程序:我怀疑这个不需要负载均衡。感谢您的帮助。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接