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.

Published Jul 24, 2018
Version 1.0
  • 235's avatar
    235
    Icon for Nimbostratus rankNimbostratus

    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

     

  • 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?

     

  • 235's avatar
    235
    Icon for Nimbostratus rankNimbostratus

    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

     

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

     

  • This is pretty cool. Good for apps running HTTP on port 443, which I have actually encountered in the past.

     

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

     

  • 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

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