Handling HTTP Requests on an HTTPS Virtual Server
There are scenarios where it might be prudent to support HTTP request redirection on a single port, and thus, a single virtual server. Yes, this can be done with the alias port zero, but that locks all other ports down unless you plan to build out a pretty extensive iRule to support the various services required for each port. This latter option is less than ideal. So what can be done?
TL;DR - only two steps required. First, check the Non-SSL Connections box in the SSL profile. Second, create an iRule to redirect non-SSL connections to SSL.
The Details
I have a test virtual server, appropriately called testvip, and on that testvip I have no iRules and a clientssl profile attached with only my certificate key chain changed from the parent profile.
ltm virtual testvip { destination 192.168.102.50:https ip-protocol tcp mask 255.255.255.255 pool testpool profiles { cssl { context clientside } http { } tcp { } } source 0.0.0.0/0 source-address-translation { type automap } translate-address enabled translate-port enabled vs-index 50 } ltm profile client-ssl cssl { app-service none cert myssl.crt cert-key-chain { myssl { cert myssl.crt key myssl.key } } chain none defaults-from clientssl inherit-certkeychain false key myssl.key passphrase none }
In this configuration, I expect that normal HTTPS requests will work just fine, and HTTP requests will fail. Let's take a look with curl, first with the working HTTPS and then the failing HTTP: (leaving curl details out for brevity here)
### HTTPS ### MY-MAC:~ rahm$ curl -v -s -k https://test.test.local/ 1> /dev/null -> HTTP/1.1 200 OK ### HTTP ### MY-MAC:~ rahm$ curl -v -s -k http://test.test.local:443 1> /dev/null -> Empty reply from server
Now that we have confirmed that the regular HTTP request is not working, let's enable non-SSL connections. Again, that's done with the checkbox in the clientssl profile:
Now let's try that second test again.
### HTTP ### MY-MAC:~ rahm$ curl -v -s -k http://test.test.local:443 1> /dev/null -> HTTP/1.1 200 OK
That's pretty cool, we successfully made an HTTP request on the HTTPS single-port virtual server! But that's not the endgame, and is most certainly not a desired state. Let's take the final step with the iRule to capture any non-SSL connections and redirect them. Here's the iRule:
when CLIENTSSL_HANDSHAKE { set https_state 1 } when HTTP_REQUEST { if { ![info exists https_state] } { HTTP::redirect https://[HTTP::host][HTTP::uri] } }
This is optimized slightly from the original iRule from gasch that inspired this article. First, we look at the CLIENTSSL_HANDSHAKE event and set a variable to true to capture that this connection is indeed an SSL connection. Then in the HTTP_REQUEST event, if that variable doesn't exist, we know that the connection is not SSL and we take the redirect action. Simple and sleek! Now, with that iRule applied, let's test again:
### HTTP ### MY-MAC:~ rahm$ curl -v -s -k http://test.test.local:443 1> /dev/null * Rebuilt URL to: http://test.test.local:443/ * Trying 192.168.102.50... * TCP_NODELAY set * Connected to test.test.local (192.168.102.50) port 443 (#0) > GET / HTTP/1.1 > Host: test.test.local:443 > User-Agent: curl/7.54.0 > Accept: */* > * HTTP 1.0, assume close after body < HTTP/1.0 302 Found < Location: https://test.test.local:443/ < Server: BigIP * HTTP/1.0 connection set to keep alive! < Connection: Keep-Alive < Content-Length: 0 < * Connection #0 to host test.test.local left intact
And there it is! You can see the HTTP request is accepted as previously, but instead of the 200 OK status, you get the 302 Found redirect. Sometimes things like this are solutions looking for problems, but conserving ports, IP space, configuration objects, etc, could all be factors.
- MichaelOLearyEmployee
Thank you for writing this Jason. Today I was asked this for the first time by a customer, and after a few searches I stumbled on to your excellent article. Very nice to know about this.
- Michelle_Anne_GNimbostratus
Hello . i have successfully done the procedure however if i type the abc.sample.com it has an connection error but if ive used abc.sample.com:443 the site loaded successfully. Help Pls
- jmsanchezcb_239Nimbostratus
Hello! I think the line HTTP::redirect https://[HTTP::host][HTTP::uri] is going to open the door to the host header poisoning vulnerability; to prevent this, the value of [HTTP::host] can be validated against a whitelist.
- Dan_PachecoCirrus
This is pretty cool. Good for apps running HTTP on port 443, which I have actually encountered in the past.
- 235Nimbostratus
Thanks @Jason Rahm
- JRahmAdmin
you might not ever need this. Some might need to allow non-SSL connections via http on the SSL port and redirect to SSL so a more secure https connection will occur, which is what this solution provides.
- 235Nimbostratus
Sorry Jason Rahm ,My English is not good. I want ask When do I need to visit the site "http" scheme's "443" port? I noticed that your test command was “curl -v -s -k ” I thinks the user don't access "http" scheme's "443" port.
Thanks
- JRahmAdmin
I'm not quite sure what you are asking. Are you are asking why someone would want to allow http cleartext connections on what should be an encrypted virtual server?
- 235Nimbostratus
Hi Jason Rahm
I don't quite understand what this scene means.
Because I don't understand AND When do user need to access your site's "http" scheme's "443" port.
Thanks