You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Lam, Eugene" <eu...@amazon.com> on 2013/04/10 02:49:45 UTC

use connection hostname for SNI and SSLProxyCheckPeerCN instead of the Host: header

Was "Re: SSLProxyCheckPeerCN / ProxyPreserveHost issue"

So, what do folks think about adding this directive to use the connection hostname for SNI and the SSLProxyCheckPeerCN feature?  Would such a directive be beneficial?  It seems a number of users who use ProxyPreserveHost will benefit from this.  It lets users revert to the behavior before the SNI change.

More details about the use-case here:
https://issues.apache.org/bugzilla/show_bug.cgi?id=54656

Eugene Lam

From: <Lam>, "Lam, Eugene" <eu...@amazon.com>>
Reply-To: "dev@httpd.apache.org<ma...@httpd.apache.org>" <de...@httpd.apache.org>>
Date: Friday, March 8, 2013 6:27 PM
To: "dev@httpd.apache.org<ma...@httpd.apache.org>" <de...@httpd.apache.org>>
Subject: Re: SSLProxyCheckPeerCN / ProxyPreserveHost issue

Hi folks,

I came across an old issue that was discussed previously under "SSLProxyCheckPeerCN / ProxyPreserveHost issue":
http://mail-archives.apache.org/mod_mbox/httpd-dev/201209.mbox/%3C50462600.7010607@kippdata.de%3E

However, I think I have found a legitimate use-case where I do want Apache to behave in the old way.  I've detailed the use case in this new bugzilla issue:
https://issues.apache.org/bugzilla/show_bug.cgi?id=54656

Assuming that the new behavior since 2.4.3 will be the default going forward, I'm proposing a new directive [1] which would allow Apache in reverse proxy to use the connection hostname for SNI and SSLProxyCheckPeerCN instead of the Host: header.  This directive will be added when ProxyPreserveHost is on.

I'm curious what your thoughts are on the use case and this proposed directive.

Eugene

[1] https://issues.apache.org/bugzilla/attachment.cgi?id=30029 (I forgot to add a text extension, so please save it before opening)


Re: use connection hostname for SNI and SSLProxyCheckPeerCN instead of the Host: header

Posted by Ruediger Pluem <rp...@apache.org>.

Tom Evans wrote:
> On Fri, Apr 12, 2013 at 7:18 AM, Lam, Eugene <eu...@amazon.com> wrote:
>> 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" <ht...@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.
>>
>>
> 
> I must be missing something. With ProxyPreserveHost, the backend must
> respond to requests for the frontend hostname. If so, and you wish to
> use SSL for the proxy connection, you should set up the backend so
> that it does have the required certificate, or don't use
> ProxyPreserveHost.
> 
> This whole thing seems to be "I told the proxy to treat
> backend.example.com to act as www.example.com, backend responds to
> www.., but I didn't give it www's certs, so validation fails".
> 
> Using ProxyPreserveHost implies that the backend will correctly
> respond to requests with the frontend's hostname, if that is not the
> case, don't use ProxyPreserveHost.

Or use SSLProxyCheckPeerCN off

Regards

Rüdiger


Re: use connection hostname for SNI and SSLProxyCheckPeerCN instead of the Host: header

Posted by Tom Evans <te...@googlemail.com>.
On Fri, Apr 12, 2013 at 7:18 AM, Lam, Eugene <eu...@amazon.com> wrote:
> 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" <ht...@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.
>
>

I must be missing something. With ProxyPreserveHost, the backend must
respond to requests for the frontend hostname. If so, and you wish to
use SSL for the proxy connection, you should set up the backend so
that it does have the required certificate, or don't use
ProxyPreserveHost.

This whole thing seems to be "I told the proxy to treat
backend.example.com to act as www.example.com, backend responds to
www.., but I didn't give it www's certs, so validation fails".

Using ProxyPreserveHost implies that the backend will correctly
respond to requests with the frontend's hostname, if that is not the
case, don't use ProxyPreserveHost.

Cheers

Tom

Re: use connection hostname for SNI and SSLProxyCheckPeerCN instead of the Host: header

Posted by "Lam, Eugene" <eu...@amazon.com>.
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" <ht...@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


Re: use connection hostname for SNI and SSLProxyCheckPeerCN instead of the Host: header

Posted by Kaspar Brand <ht...@velox.ch>.
On 10.04.2013 02:49, Lam, Eugene wrote:
> Was "Re: SSLProxyCheckPeerCN / ProxyPreserveHost issue"
> 
> So, what do folks think about adding this directive to use the
> connection hostname for SNI and the SSLProxyCheckPeerCN feature?
> Would such a directive be beneficial?  It seems a number of users who
> use ProxyPreserveHost will benefit from this.  It lets users revert
> to the behavior before the SNI change.

It's not really "the SNI change" which is the issue, it's the question
of whether you want to ignore cert name mismatches. From your PR:

> 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.

> 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

Kaspar