This might sound like an idea from an overcautious paranoid guy. But it’s not: My customer is in a very sensitive business.
Somebody may scan the internet for open ports and, by random, connect to my customer’s IP. This person will send a request and see my customer’s gateway. He might get curious, even though the gateway is not branded at all and the hostname is not meaningful (if you don’t know what it means).
My first idea was to block all requests with
HTTP.REQ.HOSTNAME.EQ("gateway.norz.at").NOT. This works well, however, it is not a sufficient solution, as a potential hacker would receive a certificate for norz.at, so he would know about the hostname, there would be a certain risk for guessing even if the certificate is a wildcard certificate for *.norz.at.
I would not do this to my own site, I want everybody to be able to see my content, but I could consider doing it to my gateway.
A look behind the Scenes
So I had to look at the SSL connection establishment phase. There are four packets sent:
- the Client Hello
- the Server Hello (including the certificate), usually 2 or more packets.
- Client Key Exchange, a Change Cipher Spec from the client
- a Change Cipher Spec from the server
The most interesting packet is the Client Hello.
The client hello packet, when connecting to the IP address:
So the only thing we would have to do is check the presence and content of the SNI header. That should be an easy one. Unfortunately, I could not find it in the responder policies. Strange enough, CLIENT.SSL does not offer SNI. So I started googleing. I came across this article. It suggests an SSL Policy like that:
add ssl policy snipolicy -rule client.ssl.client_hello.sni.contains("abc") -action pick_ca_group.Sounds like a good approach. So I did my policy like that:
add ssl policy ssl_pol_sni-header -rule "CLIENT.SSL.CLIENT_HELLO.SNI.CONTAINS(\"norz.at\").NOT -action RESET. I bound it to my webserver, but it blocked all connections, no matter which SNI header I sent. I tested it, both with the current 13.1 and current 13.0 versions. I guess, there is a bug in the current firmware.
I had to rethink. I also looked into SSL profiles but with no success.
What really worked for me
What is the SNI header good for? Sure, it should help a server with plenty of certificates bound to select the proper certificate! Perfect, that’s exactly what I want. It should select the right certificate, and select nothing in case the user failed to send a certificate.
So I created an SSL vServer, turned on SNI, and bound just a single certificate to it, with SNI enabled. Even better approach: Use an SSL profile with SNI enabled. That’s what I did with my customer. I don’t like SSL settings, instead, I usually enable the default profile (see here).
set ssl vserver lb_vs_norz.at_secure -dtls1 DISABLED -SNIEnable ENABLED
bind ssl vserver lb_vs_norz.at_secure -certkeyName crt_norz.at -SNICert
The effect was exactly what I expected: A user connecting to https://norz.at will see the content, while a user connecting to https://126.96.36.199 will be rejected. I took a look at the networking part. That’s what happens behind the scenes:
Problems to consider
It does not make sense if norz.at owns, for example, IPs from 188.8.131.52-48. I would be able to guess a hostname for 184.108.40.206, especially, if the certificate bound is a wildcard certificate for norz.at. The server would react to requests for https://anything.norz.at. The IP address for a well-hidden gateway should be very different from all other IPs the organization uses, and it should not use a wildcard certificate.
The hostname should be very different from the hostname used for the public internet presentation. It would make sense to use an FQDN from a totally different domain. On the other hand, employees should be able to remember this FQDN. So in case the organization’s name is Shlemazl INC, the company’s website is shlemazl.biz, I would suggest using something like s-inc.net. Easy for an employee to remember, hard for a hacker to guess.