How to ensure a secure connection using a reverse proxy to an external server? - apache

Guess this is the only post ever where I start with: "My SSL connection works but I don't know why".
I have a setup where the domain name and wildcard certificate lie on server A, and I want to use a subdomain of that domain to proxy requests to server B on another machine somewhere on the internet. Server B is currently only reachable via an IP, so I actually did not expect this to work, because SSL-certificates are based on domain names.
My setup is as follows (example):
Server A domain: www.production.io
Server A Subdomain: cus1.production.io
Server B IP: 65.23.523.12
Apache config for http of cus1.production.io:
RequestHeader set X-Forwarded-Proto "https"
ProxyPreserveHost On
Redirect / https://cus1.production.io/
Apache config for https of cus1.production.io:
ProxyPass / http://65.23.523.12/
ProxyPassReverse / http://65.23.523.12/
Calling cus1.production.io shows the application on 65.23.523.12 but with a secured connection (green lock) in the browser though the webserver on Server B does not offer https connections nor does it provide an SSL certificate.
Although the connection between a client and the "proxying" Server A is secure, the data transferred to the actual application is not. So this is actually a fraud.
Question: How do I make sure a secure connection will be applied between Server A and Server B?

It's not really "fraud", it's just that the SSL/TLS connection is ensured between the browser and Server A. The browser has nothing to do with Server B: Server A is the client to Server B.
If you can, set up SSL/TLS on Server B. Even if it's only accessible with an IP address, you could create your internal CA or a self-signed certificate. (That certificate should have this IP address in a SAN entry of IP address type.)
Then, you can use mod_ssl's SSLProxy* options to configure how Apache Httpd (on Server A) behaves as a client to server B (i.e. when it's a reverse proxy).
Typically, you'll need to set SSLProxyCACertificateFile (to point to your internal CA cert or that self-signed cert) and use SSLProxyCheckPeerName.

In short, it's up to you to make sure.
What you've just described is a common way of configuring SSL setups, where you have one set of servers that handle the secure connection to the browser, then they proxy the requests to another server, often just with http. This is known as ssl termination.
Usually this connection is done within a secure network, the servers hosting the certificates can be accessed from the internet, but the servers they forward to are not, so they don't proxy back across the internet. However, there is nothing in theory to prevent this if your servers aren't configured properly.

Related

Let's encrypt certificate with NO SNI

I have a site where i have ssl created by letsencrypt, but there is a problem with no sni ssl. Is it confugired ok?
https://www.ssllabs.com/ssltest/analyze.html?d=watcheds.com
Site looks good https://watcheds.com .
I
Your site is almost certainly hosted on a virtual host with many other sites on the same IP address. As such, HTTPS won't work without SNI because the server can't know which virtual host the client wants to connect to. The raw data in a TCP connection only has the IP address and port. The HTTP data is all in the packet content, which is encrypted in HTTPS.
SNI access works via HTTPS because the desired site is passed unencrypted and in the clear, allowing the server to properly route the incoming connection without access to your site's private SSL keys. Without SNI, the server would need to decrypt the incoming HTTPS request before knowing where to route it, and this would require the server to have access to your site's private keys.
And if the server were hosting many virtual hosts, without something like SNI it wouldn't know which set of private keys to use...

Multiple domains and SSL : all domains use my SSL certificate but I don't want?

I have a wildcard SSL certificate on my apache server. It works perfectly with my domain, but the mistake is that it works with all the domains on my apache server ! And I don't want it, when I go on https://www.mywebsitewithouthttps.com, firefox tell me that the page is not secure because the certificate is for www.mydomainwithhttps.com. If I add an exception for this SSL error on my browser, it is not "mywebsitewithouthttps.com" that is display but "mydomainwithhttps.com" (on this URL : https://www.mywebsitewithouthttps.com) !
I don't want my certificate to work for all the other domains ! It's a big problem because Google is crawling and indexing all my other domains on HTTPS with the content of mydomainwithhttps.com :-(
This my virtualhost for SSL :
NameVirtualHost *:443
<VirtualHost *:443>
ServerName www.mydomainwithhttps.com
DocumentRoot "/home/mydomainwithhttps/www"
suPHP_Engine On
suPHP_AddHandler x-httpd-php
suPHP_UserGroup mydomainwithhttps users
AddHandler x-httpd-php .php
SSLEngine on
SSLCertificateFile /certificates/ssl_certificate.crt
SSLCertificateKeyFile /certificates/www.mydomainwithhttps.com.key
SSLCACertificateFile /certificates/IntermediateCA.crt
</VirtualHost>
If you make a HTTPS request the client will establish a TCP connection to the relevant IP and port (usually 443) at the server. If the connection succeeded it will start the TLS handshake and during the TLS handshake it will get the certificate for validation.
If you have multiple servers at the same IP address and port they all share the same TCP listener. Since the TCP connection attempt has no information about the targets server name but only has the targets IP address and port the listener will accept all connection attempts, even if the (yet unknown) target hostname has no HTTPS configured.
Modern clients then send the target hostname inside the TLS handshake and only then the server knows what the client wants. If it has HTTPS configured for the requested name the server can send the appropriate certificate. If HTTPS is not configured for this name the server will either send a default certificate or close the connection (maybe send a TLS alert when closing).
In summary this leaves you with the following options:
Use a different IP address for HTTPS sites and non-HTTPS sites. This way the TCP connection will already fail because the server is not listening for connections on this IP:port.
Configure your server to return an error when the client requests a hostname for which no HTTPS is configured. This way the client will probably get some strange error message about HTTPS problem in the browser. I'm not sure but maybe you can setup Apache this way when using the SSLStrictSNIVHostCheck on option. If this option does not help then apache might not support this kind of setup.
Configure your server to use a default certificate (usually the first configured certificate) whenever the name does not match or the client does not support SNI. The client will get a certificate mismatch warning in the browser. This is the setup you currently have.
Setup HTTPS properly for all domains either by having separate certificates or by including them all into a single certificate.
Thus to make sure that the bots don't assume that your site can do HTTPS you need to go with option 1 or 2. Please note also that in all of these cases you expect the bots to support SNI, which not all do. Therefore for best compatibility you would need to use a separate IP address for each HTTPS site.
You can configure the multi domain with SSL and with different certificate on both UBUNTU and RHEL by following multi donain with ssl
The problem is that Apache will try to find config for https://www.mywebsitewithouthttps.com/ and when it doesn't, it will default back to the first https config (the one for mydomainwithhttps).
This will show a cert error but, as you've experienced, if you click through, you see the wrong site.
I cannot however understand Google crawling and indexing the site. I would have thought it would have stopped when it saw the cert error? I'd be very surprised if that is not the case but if it's not you can put a rewrite rule on for those hostname a to redirect back to http.
There's only 2 ways around this:
Get certs for the other domains so you can connect via https. You can still redirect back to http if you really want.
Separate out the servers with https to a different server (or a different IP on the same server and set up Apache config to listen on port 443 on https IP address only).
That's just the way Apache (and most - if not all - other webservers) work.

Redirect HTTPS 443 Port to multiple sites on other servers

The scenario is this: On side "A" where I stay I can only use 443 for HTTPS from the browser, no other port is enabled for HTTPS requests. In the side "B" I have multiple HTTPS sites in different LAN servers behind one IP address to Internet.
Is a possible way to do something to access the multiple HTTPS Sites from the side "A"?. If I do port forwarding on the side B like: from side A :443 to side B : it works but only for one of the HTTPS sites.
I looked in to installing an Apache Server with SNI (server name indication) to do www.sideb.server1.com:443 and www.sideb.server2.com:443 to the only IP Address on side B and different servers, but don't know if I can "transfer" the traffic from that server to another one. Redirects, I assume, do not work because the client on side A cannot access other ports from side B.
It should be possible to let apache or ngnix work a a reverse proxy and forward the data to the right host based on the server name the clients sends using SNI. But, in this case all the certificates need to be located at side A, so that the reverse proxy can terminate the SSL connection with the correct certificate. And, client certificates will not work.
In theory there is another option: one could write a kind of proxy, which just looks at the initial SSL Client Hello (e.g the first packet sent from the client), extracts the clear-text server name extension and then forwards the whole connection to the right host. In this case you don't need to have the final certificates at the proxy side because you don't terminate the connection and client certificates will also work. Maybe someone has coded this already.

Is it possible to have a forward proxy with ssl encryption between the proxy and the user?

First of all I want to make clear that i am not talking about accessing content which is on origin servers that deliver using https which can be done using the module mod_proxy_connect.
What I want is a secured connection between the client and the proxy, also when the origin that is requested actually is served by an unsecured standard http server.
I am using apache 2.2 and also would like to make this possible with apache if that works.
I sniffed some requests using wireshark and noted the following:
A usual http of the url http://example.com/file looksl ike this:
on a connection to the origin server:
GET /file HTTP 1.1
Host: example.com
Note that the host information is stripped from the actual request and the host header is supplied instead (which can be handled server side in named virtual hosts).
When the request goes through a proxy server it looks slightly different:
on a connection to the proxy server:
GET http://example.com/file HTTP 1.1
Host: example.com
Note that the request line now actually contains the full url including protocol and hostname.
The host header is probably redundant, bus if I read the RFC correctly it is required by HTTP 1.1.
So I think about setting up an apache webserver listening on port 443, enable a virtualhost with ssl engine and certificates up and do not bind it to any hostname.
I think that should get apache to talk ssl, but however the certificates common name will not match the host specfied in the connect line to the proxys server ip adress.
Is what I want to to even possible with current standards and if so how can I do it?
Yes of course, that's what HTTPS proxy is.
Client connects to proxy over SSL, sends commands to proxy in text.
It is also possible to use HTTP CONNECT to establish HTTPS connection "inside" the SSL connection to HTTPS proxy, though not all clients support this:
HTTPS connection over HTTPS proxy
client proxy server
ssl \-------/ ssl
connect---------200 OK
ssl \---------------------------/ ssl
data-------------------------------data
/---------------------------\
/-------\
HTTP connection over HTTPS proxy
client proxy server
ssl \-------/ ssl
GET http://server/ ->
GET /
Host: server ->
<---------OK, data
<--------------OK, data
/-------\

validate SSL certificate on a shared hosting

according to this question all HTTP header when we are using HTTPS are encrypted(including request URI and Host header).
when browser want to browse a page on website that using HTTPS, it first create secure connection, then it sends HTTP request(encrypted) and server return the answer to browser. Now assume there are more than one secure website with more than one SSL certificate, so when server want to create secure connection how does it detect which certificate should be used because it doesn't know anything about request!!!
Since the SSL channel is negotiated prior to the reception of the Host header, an HTTPS server can use at most one certificate per bound IP endpoint (IP address and port). In other words, to use two different SSL certificates, you will either need to bind each virtual host to a different port, or a different IP address.
Before TLS the server indeed didn't have a way to know certificate of which host it should present to the client and this caused problems.
In TLS there was a special extension named Server Name introduced (see RFC 3546), which lets the client tell the server, what host the client wants to connect to. Based on contents of this extension the server can present proper certificate. Of course, all of this requires that TLS and the extension itself are supported and used by both parties.
The basis of this is to provide a SSL key(set) for each virtual server.
In Apache, for example, it's relatively simple. Each shared site is likely in a <VirtualHost> directive. The SSL keys can be specified within that, and thus apply to that virtual host only.
Rough example:
<VirtualHost *:443>
ServerName server.com
SSLEngine on
SSLCertificateKeyFile /etc/ssl/server_com.key
SSLCertificateFile /etc/ssl/server_com.crt
SSLCertificateChainFile /etc/ssl/server_com.ca-bundle
The server will then use the specified keys for all requests directed to that site over HTTPS. Further details on the Apache site. Similar things should apply to most web servers that support a concept of virtual hosts.
You won't get any errors, as the certificate and domain name match up.