Forum Discussion

Juraj_314736's avatar
Juraj_314736
Icon for Nimbostratus rankNimbostratus
Sep 20, 2017

TLS/1.0, PCI, and a custom message for HTTP response status codes

By June 30, 2018 we would like to turn off TLS/1.0 on all our HTTPS websites, in order to be compliant with PCI requirements.

Instead of just turning TLS/1.0 off, we would like to use that time between now and June 30, 2018 to seamlessly phase the TLS/1.0 out.

To do so, our F5 still supports all TLS protocols (TLS/1.0, TLS/1.1, and TLS/1.2), but only the clients supporting TLS/1.1 and above get the actual website content. Everyone else (clients supporting TLS/1.0 only) gets a custom error page informing them about the browser upgrade requirement.

To achieve that, I'm using the HTTP status code "426 Upgrade Required". Please see:

The expected result is:

 

HTTP/1.1 426 Upgrade Required
Upgrade: TLS/1.1, HTTP/1.1
Connection: Upgrade


... Human-readable HTML page describing why the upgrade is required
    and what to do if this text is seen ...

 

Unfortunately, F5 gives me the following result:

 

HTTP/1.1 426 Unknown Code
Upgrade: TLS/1.1, HTTP/1.1
Connection: close


... Human-readable HTML page describing why the upgrade is required
    and what to do if this text is seen ...

 

My iRule looks like this:

 

 Detect TLSv1.0 protocol and send HTTP 426


when HTTP_REQUEST priority 150 {

    if { [SSL::cipher version] equals "TLSv1" } {
        log local0. "TLS/1.0 connection detected from [IP::client_addr] for [HTTP::host]"
        HTTP::respond 426 -version auto content $static::obsolete_browser_page noserver "Upgrade" "TLS/1.1, HTTP/1.1" "Content-Type" "text/html" "Cache-Control" "no-cache" "Retry-After" "60" "Connection" "Close" 
        event disable
        return
    }
}

 

If I use "Connection" "Upgrade" in the HTTP::respond code, as defined in the aforementioned RFC2817, F5 replaces it with Connection: Keep-Alive in the actual response which is being sent back to the client.

My questions are:

Question 1: is there a way in F5 to replace the message in HTTP response, so that it says:

HTTP/1.1 426 Upgrade Required

instead of

HTTP/1.1 426 Unknown Code

Question 2: is there a way to force F5 to send HTTP header that says:

Connection: Upgrade

instead of

Connection: close

or

Connection: Keep-Alive

  • BinaryCanary_19's avatar
    BinaryCanary_19
    Historic F5 Account

    this is not very elegant, but:

    it may be possible to use SSL::respond which allows you to inject raw payload directly into the SSL layer, if this is something you have room to experiment with.

    If you go this route however, you may have to make sure that this connection cannot be used for other requests, as I am not sure what effect injecting data into the stream will have on the HTTP profile state machine. So you should consider, including Connection: close in your response, calling HTTP::disable, Dropping the SSL session with SSL::session invalidate, and closing the TCP connection with TCP::close once done.

  • Very well versed question, kudos for that.

     

    I fiddled around a bit with this in my lab but came to he same conclusion as you did. Maybe you could have an Apache/NGINX server that could do this for you? Or maybe iRulesLX?

     

    Just brainstorming...

     

    /Patrik

     

  • A client capable of TLSv1.2 should not connect as TLSv1.0 in the initial instance, so there should never be a valid reason to try to get a browser to upgrade from TLSv1.0 to TLSv1.2.

     

    The Client Hello contains a protocol_version that specifies the lowest version that the client supports, and a client_version that contains the highest TLS version the client supports. The server then responds with the highest version it supports within those two limits. The result is that the client should always connect with the highest TLS version that the client and server can support.

     

    Any client that connects as TLSv1.0 can only connect at TLSv1.0. Your response should be a 200 Response that informs the customer that they need to upgrade their browser.

     

    I'll also add that RFC2817 was intended to drive a TLS protocol upgrade within an unencrypted tcp connection, similar to STARTTLS, allowing virtual hosting for encrypted connections. The adoption of Server Name Indication for SSL has provided a suitable solution to this problem, so RFC2817 is still a proposal after 17 years with no strong drivers for implementation.

     

  • Thank you both, BinaryCanary and Patrik for your responses.

     

    To be honest, I do not feel that comfortable to fiddle around with the payload directly on the SSL layer. Unfortunately, I'm not that skilled with iRules. If you have a working example that I could use or modify, I would definitely give it a try.

     

    Regarding the repurposing Apache/Nginx for this, it would be a step backwards for us, because we've just recently migrated the entire website from NGINX/HAPROXY to F5.

     

    Regarding the iRulesLX, I don't even know what it is; googling it right now :)

     

  • JG's avatar
    JG
    Icon for Cumulonimbus rankCumulonimbus

    Here's a quick and easy one for this situation based on the responses above:

     

    when HTTP_REQUEST {
        switch -exact [SSL::cipher version] {
            "TLSv1.2" {
                 do nothing
            }
            "TLSv1.1" {
                 do nothing
            } default {
                HTTP::respond 403 content {
    
    
    Access Denied
    
        You are using a Web browser that is not secure for accessing confidential information. Please upgrade to the most recent version./font>
    
    
    } "Content-Type" "text/html" Connection close
                TCP::close
                return
            }
        }
    }