Forum Discussion

Maxim_Taskov_90's avatar
Maxim_Taskov_90
Icon for Nimbostratus rankNimbostratus
Mar 07, 2006

HTTP to HTTPS and Back

Hi, I am sorry if this question has been asked before but I could not find an answer anywhere...including F5 Tech Support.

 

 

I have two virtual servers, one HTTP and one HTTPS, for the same Web site. My objective is to provide HTTP, TCP/80, access to all areas of the Web site except 2 pages, where I want to force the client to redirect to HTTPS, TCP/443. To accomplish this, I have deployed the following rule and assigned it to the HTTP virtual server for the Web site:

 

 

when HTTP_REQUEST {

 

if { [HTTP::uri] contains "/getting_started/contact_email.asp"} {

 

HTTP::redirect "https://[HTTP::host][HTTP::uri]"

 

} elseif { [HTTP::uri] contains "/moving/help_request.asp"} {

 

HTTP::redirect "https://[HTTP::host][HTTP::uri]"

 

}

 

}

 

 

So far I am happy but...now, once the user has been redirected to HTTPS, they stay on the HTTPS virtual server and never go back to using HTTP for any of the Web site areas. The site is using standard relative paths, so the behavior is understandable; however, it does not work for me. So my questions is...What do I do to redirect clients back to using the HTTP virtual server after they are done using any of the above 2 Web pages?

 

 

Thanks for your help.
  • I'm assuming from your post that you have two virtual servers (one for HTTP and one for HTTPS). If that is the case you can have two rules with the reverse logic in each.

    I'd also suggest using a class list (data group) to contain your urls. It's much easier to manage that way and then you can change them in one place if you need to. You'll need to add these values into a data group in the iRules section of the GUI. If you don't want to use a data group, you can replace the if statement with two string compares separated by a logical OR.

    class secure_uris {
       "/getting_started/contact.asp"
       "/moving/help_request.asp"
    }

    For your HTTP virtual do something like this:

    when HTTP_REQUEST {
       if the uri starts with one of the values in the
       secure_uris list, then redirect to the HTTPS version
      if { [matchclass [HTTP::uri] starts_with $::secure_uris] } {
        HTTP::redirect "https://[HTTP::host][HTTP::uri]"
      }
    }

    For your HTTPS virtual:

    when HTTP_REQUEST {
       if the uri doesn't start with one of the values in the
       secure_uris list, then redirect to the HTTP version
      if { ! [matchclass [HTTP::uri] starts_with $::secure_uris] } {
        HTTP::redirect "http://[HTTP::host][HTTP::uri]"
      }
    }

    Or, if you want a single rule that you can apply to both virtuals, you can distinguish HTTP vs. HTTPS via the TCP::local_port value.

    when HTTP_REQUEST {
      if { [TCP::local_port] == 80 } {
         if the uri starts with one of the values in the
         secure_uris list, then redirect to the HTTPS version
        if { [matchclass [HTTP::uri] starts_with $::secure_uris] } {
          HTTP::redirect "https://[HTTP::host][HTTP::uri]"
        }
      } else {
         if the uri doesn't start with one of the values in the
         secure_uris list, then redirect to the HTTP version
        if { ! [matchclass [HTTP::uri] starts_with $::secure_uris] } {
          HTTP::redirect "http://[HTTP::host][HTTP::uri]"
        }
      }
    }

    This hasn't been tested, but should give you something to get you going.

    -Joe
  • unRuleY_95363's avatar
    unRuleY_95363
    Historic F5 Account
    Joe,

     

    That will work fine assuming the SSL is terminated on the BIGIP. If not, the BIGIP can't inspect the content of the HTTPS connections to determine if the client has moved out of the secure uri's.

     

     

    Just thought I'd point that out.
  • Thanks for the fast an professional response Joe. Looks like the modified iRule will work perfectly for my case but I will test it and I will post the results here tomorrow.

     

     

    To answer unRuleY's concern, yes, I am terminating the SSL at the BIG-IP, so I think using the HTTP_REQUEST event type should be OK.

     

     

    Thank you both again!
  • I tested the rule, the one that combines the HTTP and HTTPS logic, and it works perfect. However, I used the "contains" rather than the "starts_with" relational operator considering the fact that the URI will not necessarily start with the path but the class path can be deeper in the URI string.

     

     

    Is there any particular benefit to using "starts_with" rather than the "contains" relational operator?

     

     

    And one final question...

     

     

    From performance and optimization point of view...is it better to use one iRule combining the forward and reverse logic for the HTTP and HTTPS virtual server, and assign it to both virtual servers, or is it better if the iRule is split in half and the forward logic is assigned to the HTTP virtual server and the reverse to the HTTPS virtual server?

     

     

    Thanks for your support.
  • The only benefit of using "starts_with" over "contains" is to check whether the uri is at the start of the request. There is no significant performance improvement from one to the other.If you use the contains, then all of these requests would match

     

     

    http://server/getting_started/contact.asp

     

    http://server/some_path/getting_started/contact.asp

     

    http://server/some_other_path/page.html?foo=/getting_started/contact.asp

     

     

    Not that this is likely to happen, but it's an option. To be the safest, you should put all known paths in your secure_uri's class and use the starts_with operator. But, if you aren't concerned with rogue uri's circumventing your logic, then the contains should work just fine.

     

     

    With regards to performance on the rule itself. You are probably better off with two rules so you don't have the overhead of the check on the server port in each request. But, that overhead is fairly negligible so you should pick the option that is most maintainable for you.

     

     

    -Joe
  • I spoke too early...everything is good with the rule but I have one small issue...now Internet Explorer alerts you about 6 times that you are moving from secure to non-secure connection before you actually see the page. This happens because the HTTP-to-HTTPS logic send you secure if you visit a certain page, but then the HTTPS-to-HTTP logic sends you non-secure if you are visiting a page other than the one in the specified class. Well, there a number of includes within each page that the HTTPS-to-HTTP logic sends non-secure and the users see the Internet Explorer message multiple times.

     

     

    Do you know of any good way to say "any resource within a given page", without explicitly specifying the exact path of each resource?
  • You have two options:

     

     

    1. fully qualify your urls to start with http:// in your HTML content. That way in the HTTPS responses it will specify http://... in the links an no redirect error will be issued.

     

     

    2. If this isn't an option, you can do so within an iRule by inspecting the HTTP::payload in the HTTP Response. There's an example of this over in my blog (Click here).

     

     

    -Joe
  • Thanks Joe. Your comments were very good and detailed. Unfortunately, I can't use either of them in my environment and I think I will go the path of using a more comprehensive URI class list to avoid the need for negative logic, which is the root cause of the redirect issue.

     

     

    Thanks again for your help.
  • Hi Folks,

     

     

    this is great information on HTTP/HTTPS redirection. in particular the use of classes and data groups. i've definitely picked up some solid tips.

     

     

    on the topic of http/https redirection . . . have any of you encountered loss of client-side application session variables when switching back and forth between SSL and non-SSL connections? we use similar redirection techniques in our environment, but we are suspicious of the HTTP::redirect method and the issued HTTP 302 causing the browser to flush the client-side session variables.

     

     

    this seems to cause a problem if the browser is storing session info with a web or application server on the backend while using a HTTP session, and the iRule then parses the URL, decides to HTTP::redirect to "https://..." - so when the browser request lands on the back-end server again, it shows up with no session variables.

     

     

    recently, i've converted some of the enforced SSL iRules over to using something along these lines . . .

     

     

    when HTTP_REQUEST {

     

    if {[HTTP::uri] equals "/secureThatLinkIfYouWill } {

     

    HTTP::respond 301 Location "https://[HTTP::host][HTTP::uri]" }

     

     

    This seems to allow all of the client-side cookies to stay in-tact while switching back and forth, but on occasion, after a redirection, all of the client-side cookies are "gone"!

     

     

    are these suspicions legitimate? are there any bullet-proof ways to prevent this?

     

     

    I've been looking around for an elegant way to maintain session/state while allowing a smooth transition between HTTP/HTTPS connections for quite some time, so any tips would be greatly appreciated.

     

     

    Thanks,

     

    -ag