Sunday, October 2, 2016

*Securing CloudFlare's FlexibleSSL even further using UFW

NOTE: This page has moved to

In previous posts, I have mentioned how I am using CloudFlare's Flexible SSL to help secure this site.  From those posts you will remember that Flexible SSL means that your browsing session is encrypted between your browser and CloudFlare but possibly not encrypted between CloudFlare and the actual server which holds the data.  This causes the data flow to look like:

In the case of this web-site, for example, Blogger does not support HTTPS on custom domains, so the HTTP connection shown above exists here as well.
NOTE: As mentioned earlier, this site does not contain any personal information or allow anyone to login.  Therefore the underlying HTTP connection is of no security consequence.  If you can hack into this site, I encourage you to submit a report to the Google Bug Bounty program and get paid for your discovery.
Those of us that understand networking can see from above that it should be possible to bypass CloudFlare and get directly to the unencrypted HTTP port on the Apache server.  This is indeed true if you can determine the actual IP address of the Apache server.

This could potentially be a security hole that needs to be patched.  Fortunately, through the magic of scripting and the Uncomplicated Firewall (UFW) or any other firewall, we can shutdown this hole.

If you are running on a Linux server, take a look at this little script I have put together.  The basic flow of this script is to:
1) Download a list of known CloudFlare IP addresses - provided by CloudFlare
2) Parse each entry into a UFW command to permit access from CloudFlare to a specific port

The results of this script are that the Apache server will only accept connections coming from the CloudFlare network.  This does not encrypt the connection between CloudFlare and your Apache server, but it does prevent anyone from bypassing CloudFlare.

Here is the script:

function to_int {
    local -i num="10#${1}"
    echo "${num}"

function port_is_ok {
    local port="$1"
    local -i port_num=$(to_int "${port}" 2>/dev/null)

    if (( $port_num < 1 || $port_num > 65535 )) ; then
        echo "*** ${port} is not a valid port" 1>&2
        return 0

    #echo 'ok'
    return 1

function addRules {
    for a in `curl -s`
       #echo ufw allow to any port $PORT proto tcp from $a
       ufw allow to any port $PORT proto tcp from $a

function removeRules {
    for a in `ufw status numbered | grep $PORT/tcp | cut -c45-`
       #echo ufw --force delete allow to any port $PORT proto tcp from $a
       ufw --force delete allow to any port $PORT proto tcp from $a

if [ "`whoami`" != "root" ]; then
   echo ABORT: This script must be run as root
   exit 1

port_is_ok $2
#echo $port_is_ok
if [ $port_is_ok -eq 0 ]; then
   echo "Usage: $0 <add|remove|refresh> <port number>"
   exit 0

case "$1" in
      echo "ABORT: Usage $0 <add|remove|refresh> <port>"
      exit 1
You can see from the "usage" line, that the command format for this script is:
Usage: <script> <add|remove|refresh> <port number>
Here is what each of the command means:
1) add is to allow access from CloudFlare to a port
2) remove is to remove access from CloudFlare to a port
3) refresh is a combination of remove then add - to make sure that you have all of the current CloudFlare IP addresses

A few warnings about this script:
1) It must be run as root - but could be modified to allow anyone who can issue ufw or iptables commands via sudo
2) It only processes CloudFlare IPv4 addresses - but can be modified to allow IPv6 as well (the URL for CloudFlare's IPv6 addresses is
3) It currently issues ufw commands but could be easily modified to support iptables (or any other firewall) commands

Good luck - and enjoy your more secure CloudFlare network.