ASM/WAF rate limit and block clients by source ip (or device_id fingerprint if needed) if there are too many violations by them
You can see my code about how to block users by source ip address that test if the servers and are vunrable to web attacks:
when RULE_INIT {
# The max requests served within the timing interval per the static::timeout variable
set static::maxReqs 3
# Timer Interval in seconds within which only static::maxReqs Requests are allowed.
# (i.e: 10 req per 2 sec == 5 req per sec)
# If this timer expires, it means that the limit was not reached for this interval and
# the request counting starts over. Making this timeout large increases memory usage.
# Making it too small negatively affects performance.
set static::timeout 60
}
#when CLIENT_ACCEPTED {
#set cIP_addr [IP::client_addr]
# set getcount [table lookup -notouch $cIP_addr]
# if { ! ( [class match $cIP_addr equals ip_whitelist] ) } {
# The following expects the IP addresses in multiple X-forwarded-for headers.
# It picks the first one. If XFF isn’t defined it can grab the true source IP.
# if { $getcount > $static::maxReqs } {
# log local0. "Request Count for $cIP_addr is $getcount"
# drop
# }
# }
#}
when HTTP_REQUEST {
# Allows throttling for only specific URIs. List the URIs_to_throttle in a data group.
# Note: a URI is everything after the hostname: e.g. /path1/login.aspx?name=user
if { [HTTP::header exists X-forwarded-for] } {
set cIP_addr [getfield [lindex [HTTP::header values X-Forwarded-For] 0] "," 1]
} else {
set cIP_addr [IP::client_addr]
}
set getcount [table lookup -notouch $cIP_addr]
if { ! ( [class match $cIP_addr equals ip_whitelist] ) } {
# The following expects the IP addresses in multiple X-forwarded-for headers.
# It picks the first one. If XFF isn’t defined it can grab the true source IP.
if { $getcount > $static::maxReqs } {
log local0. "Request Count for $cIP_addr is $getcount"
# drop
HTTP::respond 403 content {
<html>
<head><title>HTTP Request denied</title></head>
<body>Your HTTP requests are being blocked because of too many violations.</body>
</html>
}
}
}
}
#when ASM_REQUEST_BLOCKING {
when ASM_REQUEST_DONE {
#log local0.debug "\[ASM::status\] = [ASM::status]"
if { [ASM::status] equals "blocked" } {
# Allows throttling for only specific URIs. List the URIs_to_throttle in a data group.
# Note: a URI is everything after the hostname: e.g. /path1/login.aspx?name=user1
# if { [class match [HTTP::uri] equals URIs_to_throttle] } {
# The following expects the IP addresses in multiple X-forwarded-for headers.
# It picks the first one. If XFF isn’t defined it can grab the true source IP.
# set getcount [table lookup -notouch $cIP_addr]
if { $getcount equals "" } {
table set $cIP_addr "1" $static::timeout $static::timeout
# Record of this session does not exist, starting new record
# Request is allowed.
} else {
log local0. "Request Count for $cIP_addr is $getcount"
table incr -notouch $cIP_addr
# record of this session exists but request is allowed.
}
# }
}
}
EDIT:
Please carefully read documentation for the code as the ASM session tracking and session awerness (https://support.f5.com/csp/article/K02212345 ) are better futures as mentioned that can do simillar things but the idea for this irule to be less CPU intensive by blocking bad actors before the ASM processing.