Hi Kaspar,

Thanks for digging up that thread.  I still think SNI needs to be considered, 
but not in the way I originally thought!

On 4/10/13 9:43 PM, "Kaspar Brand" 
<httpd-dev.2...@velox.ch<mailto:httpd-dev.2...@velox.ch>> wrote:
On 10.04.2013 02:49, Lam, Eugene wrote:
ssl_engine_io.c will pull out this note and use it for SNI and
SSLProxyCheckPeerCN.  Unfortunately, www.example.com does not match
backend.example.com.

I wouldn't call this unfortunate, I would say that it's a
misunderstanding of what SSL proxying with mod_proxy_http is expected to
provide.

To help "iron out" any misunderstanding, I'll repeat what I know.  There's at 
least 2 types of ways to configure mod_proxy_http.  I'm only interested in the 
ProxyPassReverse, not ProxyPass.

In the classic *reverse proxy* setup, the CN is always different between 1) the 
cert on the reverse proxy that terminated the original HTTP request and 2) the 
cert on the backend server terminating the backend HTTP request.  In other 
words, the reverse proxy (responding to request for www.example.com) has 
already terminated the secure connection with the original HTTP requester.  The 
reverse proxy is initiating a new connection with "backend.example.com", 
assuming "backend.example.com" is what appeared in the ProxyPassReverse 
directive.  This is expected, right?

When ProxyPreserveHost is off, everything works fine.  The backend HTTP 
request's Host header would be backend.example.com, and mod_ssl sees a cert 
with CN=backend.example.com.  This is the expected behavior and is the 
supported configuration.

Turning on ProxyPreserveHost breaks this by affecting the Host header.  It 
changes the backend HTTP request from the ProxyPassReverse value into the value 
of Host header the original HTTP requester.

The reverse proxy shouldn't expect CN=www.example.com,
CN=www.example.org, etc. when the backend only has
CN=backend.example.com.

Looks like you're trying to use a "generic" SSL tunnel for any HTTP
request, irrespective of the host name in its URL. This is prone to MitM
attacks, and hardly a good idea. See also this message:

http://mail-archives.apache.org/mod_mbox/httpd-dev/201204.mbox/%3C4F8E7873.8000004%40velox.ch%3E


In my case, the intent of `ProxyPreserveHost on` is to trick the applications 
at backend.example.com into thinking it's directly getting the request bound 
for www.example.com.  The correct way would have been to rewrite applications 
to recover the info from X-Forwarded-Host, I don't deny that.  My guess is, the 
history/motivation of the ProxyPreserveHost directive is for compatibility with 
older, fossilized applications that can only understand Host header and not 
X-Forwarded-Host.  It also helps with a reverse proxy that has to talk to both 
old and new applications at the same time.

What I take away from reading "SNI with apache 2.4.1 reverse proxy" thread is: 
use ProxyPreserveHost at your own risk, it doesn't work quite right for reverse 
proxy, although it doesn't stop some users from trying.  It seems to me the 
Host header is an unstable source for SSLProxyCheckPeerCN when 
`ProxyPreserveHost on`.  Is this conclusion logical?

So, I am suggesting a patch for mod_ssl to use the "connection-level" hostname 
from ProxyPassReverse for SSLProxyCheckPeerCN.  I think it only *appears* to be 
like MitM, because the backend is returning a cert with different CN than the 
backend request's Host header.  It is still the job of the proxy server to 
decide what is expected, right?  In ProxyPreserveHost off case, it was 
expecting backend.example.com.  When ProxyPreserveHost is on, it got 
backend.example.com still; it shouldn't be any more at risk for MitM.  But, the 
backend is in a sense ignoring the SNI.  You are right in that SNI isn't my 
goal here, the goal is making SSLProxyCheckPeerCN a bit more sensible without 
turning it off completely.

Peter Sylvester<http://search.gmane.org/?author=Peter+Sylvester&sort=date> 
mentioned that "If something is put into the SNI, it must be identical to what 
is in the Host:header."  Perhaps I should leave SNI values alone, but instead 
introduce a directive called SSLProxyExpectPeerCNSupportsSNI.  If off, then 
still proceed if the backend don’t obey SNI but ends up returning a cert with 
CN equal to the connection-level hostname.  This way, SNI will still be 
attempted.  Thoughts?

Eugene Lam

Reply via email to