Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect if a tcp connection has been forwarded from a ssl connection?

The specific scenario I'm dealing with is attempting to connect to a websocket connection behind an AWS elastic load balancer, whilst enforcing https/ssl rather than http/tcp.

To enable the TCP/SSL upgrade from http/s, the protocol on the load balancer has necessarily been set to TCP rather than HTTP on port 80 and SSL rather than HTTPS on 443, both of which are forwarded onto the instance port of 80 using TCP.

However, a side effect of setting the protocol to TCP/SSL is that the x-forwarded-proto header no longer gets set, as experienced here:

Amazon Elastic load balancer is not populating x-forwarded-proto header

This makes the next challenge of 301ing any incoming requests using http/tcp to https/ssl somewhat problematic, as this typically relies on the inspecting the x-forwarded-proto header.

A little more detail on the specifics of the situation: there exists a docker container with a Meteor.js process running inside of it, which resides in turn within an AWS Elastic Beanstalk Application (which has an Nginx proxy layer by default, but this isn't accessible due to the use of docker which simply pulls a container definition from docker hub), which sits behind the aforementioned ELB.

Ultimately I'm left inspecting the headers that I have available to my application by the time the request has gone through the ELB, Nginx and docker agent layers, trying to work out if the original request made by the client started with http or https

Incoming https:// request headers:

{
    host: 'whatever.elasticbeanstalk.com',
    'x-real-ip': '999.99.99.99',
    'x-forwarded-for': '999.99.99.99',
    'cache-control': 'max-age=0',
    accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'upgrade-insecure-requests': '1',
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36',
    'accept-encoding': 'gzip, deflate, sdch',
    'accept-language': 'en-US,en;q=0.8'
}

Incoming http:// request headers:

{
    host: 'whatever.elasticbeanstalk.com',
    'x-real-ip': '999.99.99.99',
    'x-forwarded-for': '999.99.99.99',
    'cache-control': 'max-age=0',
    accept: 'image/webp,image/*,*/*;q=0.8',
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36',
    'accept-encoding': 'gzip, deflate, sdch',
    'accept-language': 'en-US,en;q=0.8',
    'if-none-match': '"141699-1446507991000"',
    'if-modified-since': 'Mon, 02 Nov 2015 23:46:31 GMT'
}

The only one of these that looks vaguely useful is the upgrade-insecure-requests header, but based on this

What is the "Upgrade-Insecure-Requests" HTTP header?

I'm pretty sure it's not.

Maybe I'm missing something however...

like image 695
Joshua Avatar asked Nov 03 '15 00:11

Joshua


People also ask

What is TCP over SSL?

"TCP over SSL" is not what you have -- it's SSL that "runs" over TCP. In HTTPS case you have HTTP over SSL over TCP. HTTP is an application-level protocol here. In case of just "SSL over TCP" you have custom application-level protocol, and with HTTPS you have standard HTTP.

What is forwarded SSL?

The X-Forwarded-Proto (XFP) header is a de-facto standard header for identifying the protocol (HTTP or HTTPS) that a client used to connect to your proxy or load balancer.


2 Answers

If the question is in fact "How can I ensure anyone visiting my website via http is redirected to https/ssl" (as indeed it turned out that this is what I meant), this is possible by

  1. Setting the Elastic Load Balancer to forward HTTP on 80 to HTTP on 80 on the instance (rather than TCP on 80 as it was before) and then forward HTTPS on 443 to TCP on 80 on the instance.

  2. "Assuming HTTPS/SSL" during the detection of the protocol: namely check if there exists an x-forwarded-proto, if it does, it's come from a http request, thus 301 to https. If one doesn't exist, assume it's https, don't redirect it (in practice I felt I might as well check to ensure the protocol was http before redirecting, but in the current set up I'm pretty sure that's the only scenario that can possibly occur).

like image 118
Joshua Avatar answered Oct 05 '22 12:10

Joshua


When you use TCP, the ELB will not inject HTTP headers such as x-forwarded-proto or x-forwarded-for. You may be able to get what you need by configuring Proxy Protocol.

like image 25
jarmod Avatar answered Oct 05 '22 12:10

jarmod