How to block unwanted User Agent using F5

There are many ways to block applications based on User Agent. You can use ActiveSyncDeviceAccessRules for EAS or EWSAllowList/EWSBlockList.

Besides this you can block those User Agnets already on a load balancer. The main difference is that then the workload is moved away from you Exchange server to the load balancer. In this post I’m going to describe the steps of one possible way to do so taken a F5 load balancer.

Requirements:

  • SSL termination on the load balancer, otherwise the load balancer doesn’t have access to the request
  • the following was tested with version 11.x. As we will use an iRule make sure that the syntax is working with your version

We are going to use a combination of a Data Group and an iRule. I will only cover a simple iRule, which is doing the job to block a given list of User Agents. I’m not going to explain how to write a complex iRule.

Create a Data Group

There are 4 types of Data Groups:

  • Address:An address data group consists of a collection of IP addresses.
  • String:A string address group consists of a group of strings, such as *.jpg.
  • Integer:An integer data group consists of a group of integers.
  • External File:You have the option to store data groups in an external file. The benefit of storing data groups in an external file is the data does not need to be sorted by the system when it is loaded, because it is stored outside of the bigip.conf file. The elements in the external data group file should be stored in comma-separated lists with a newline character after each entry. Refer to the BIG-IP Configuration Guide for more details about Data Groups.

More info could be found here.

Local Traffic|iRules|Data Group List

DataGroup01

click on Create…

DataGroup02

here I called the Data Group UnwantedAgents. Select String as type and if you want you can already add some strings. Just write the User Agent in the String field, leave the value empty and click on Add for each string.

Note: All strings have to be lowercase. Why? We will cover this later.

DataGroup03

click on Finished to create the Data Group

DataGroup04

Create an iRule

Local Traffic|iRules|iRule List

iRule01

click on Create…

iRule02

the iRule looks like this

when HTTP_REQUEST {
   # initialize variable
   set data ""
   # HTTP response
   set data "Sorry, [HTTP::header value User-Agent] is a wrong User Agent!"
   if { [class match [string tolower [HTTP::header "User-Agent"]] contains UnwantedAgents ] } {
     HTTP::respond 200 content $data "Header Blocked" "Value BlockedAgent"
     log local0. "Blocked src=[IP::client_addr] src_port=[TCP::client_port],agent= HTTP::header value User-Agent]"
     return
   }
 }

The iRule is doing the following:

On each HTTP request check if the HTTP header User Agent match one of the strings in the Data Group UnwantedAgents. If so send a response with HTTP status code 200 and the body “Sorry, [HTTP::header value User-Agent] is a wrong User Agent!”, where the used User Agent is written and log it.

Note: In order to minimize the list all values of the User Agent will be converted to lower case. That’s the reason why we have to use only lower cases in the datagroup. Otherwise they won’t match!

click on Finished to create the iRule

iRule03

 assign iRule to Virtual Server

Local Traffic|Virtual Servers|Virtual Server List

VirServer01

click on the Virtual Server, which represents your Exchange(here it is ExchangeHttps)

VirServer02

switch to the tab Resources

VirServer03

next to iRules click on Manage to add the iRule we have created before

VirServer04

select the iRul, add and click Finished to save your change

Make sure it works!

After I have succesfully created the Data Group, iRule and assigned the iRule to my virtual server I want to check that it works as expected. Therefore I’m using IE and browse the URL https://mail.tailspin.com/EWS/exchange.asmx

TestIE01

I can browse it without any issue. Now let me change the User Agent. Just press F12, switch to Emulation and change the User Agent String to a value I have defined in the Data Group

TestIE02

as expected….no access. As the iRule is doing a match you have to be carefull what strings you add to the Data Group….something like just ‘Apple’ or ‘Lync’ wouldn’t be a good idea

TestIE03

What I have implemented with the steps described above is something you could call Blacklist. A Blacklist is something re-active. If you want to be more pro-active you might want to go with a Whitelist. Within this list you would maintain only User Agents you want to allow access. This list might be a little bit shorter….

Whitelisting

If you want to do a whitelisting you just have to change the iRule to the following

when HTTP_REQUEST {
   # initialize variable
   set data ""
   # HTTP response
   set data "Sorry, [HTTP::header value User-Agent] is a wrong User Agent!"
   if { !([class match [string tolower [HTTP::header "User-Agent"]] contains WantedAgents ]) } {
     HTTP::respond 200 content $data "Header Blocked" "Value BlockedAgent"
     log local0. "Blocked src=[IP::client_addr] src_port=[TCP::client_port],agent= HTTP::header value User-Agent]"
     return
   }
 }

Note: Be very carefull with whitelisting! You need to know your clients very well otherwise you can break many things easily!

Based on URI

An advanced option is to maintain different Data Groups per protocol. The following example shows how you can maintain different lists for EWS and EAS

when HTTP_REQUEST {
   # initialize variable
   set data ""
   # HTTP response
   set data "Sorry, [HTTP::header value User-Agent] is a wrong User Agent!"
   switch -glob -- [string tolower [HTTP::path]] {
       "/microsoft-server-activesync*" {
           if { [class match [string tolower [HTTP::header "User-Agent"]] contains UnwantedAgentsEAS ] } {
             HTTP::respond 200 content $data "Header Blocked" "Value BlockedAgent"
             log local0. "Blocked src=[IP::client_addr] src_port=[TCP::client_port],agent= HTTP::header value User-Agent]"
             return
           }
    }
   "/ews*" {
        if { [class match [string tolower [HTTP::header "User-Agent"]] contains UnwantedAgentsEWS ] } {
             HTTP::respond 200 content $data "Header Blocked" "Value BlockedAgent"
             log local0. "Blocked src=[IP::client_addr] src_port=[TCP::client_port],agent= HTTP::header value User-Agent]"
             return
           }
      }   
 }   
}

in this example we have 2 different Data Groups

  • UnwantedAgentsEAS
  • UnwantedAgentsEWS

As we distinct between the URI we can examine the User Agents and try to match against different lists.

Advantage

  • reduced load on Exchange server
  • centralized management
  • only Data Group have to be maintained and not the iRule has to be re-written for each change

Disadvantage

  • complexity
  • the feature of getting an e-mail with the data of blocked or quarantined devices is not available as the request doesn’t reach the Exchange server

Conclusion

I can’t and don’t want to give you an advice. Each company has to decide how to safeguard and handle clients for its Exchange organisation. This post showed one way of blocking User Agents either via Black- or Whitelist and/or based on URI.

Please be carefull and before implementing the steps above, please: Test, test, test…..

Advertisements

3 thoughts on “How to block unwanted User Agent using F5

    • Hi Xin, the datagroup we created should be like an array and not like a hashtable. We just trying to match against a collection of strings. That’s why you don’t add values to the strings. It’s something different if you would use values as well and have an iRule, which set some data based on the string, which match with the corresponding value.

      Like

  1. You are my breathing in, I own few blogs and very sporadically run out from to brand.I think this web site has got some very wonderful information for everyone. “Anger makes dull men witty, but it keeps them poor.” by Francis Bacon.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s