1. Home
  2. Knowledge Base
  3. Web Application Firewall (IPDS WAF)
  4. Blocking malicious IPs behind Cloudflare using WAF in SKUDONET

Blocking malicious IPs behind Cloudflare using WAF in SKUDONET

When Cloudflare is used as a protection layer in front of SKUDONET, traffic behavior changes significantly. The load balancer no longer sees the client’s real IP address and instead receives the IP of Cloudflare nodes.

This has a direct impact on traditional network-based security mechanisms (L3/L4), such as IP blacklists.

Problem

In a typical scenario, traffic flows through the following chain:

Client → Cloudflare → SKUDONET → Backend

The REMOTEE_ADDR field no longer contains the client’s IP, but Cloudflare’s.

Consequences

  • L3/L4 blacklists become ineffective
  • Cloudflare nodes may be blocked instead of the actual attacker
  • The ability to filter malicious traffic by source IP is lost

Cloudflare partially addresses this issue by adding the real client IP in an HTTP header:

CF-Connecting-IP: <real client IP>

Therefore, filtering must move from the network layer (L3/L4) to the application layer (L7).

Solution

The solution is to move blacklist logic to the WAF (Web Application Firewall), where HTTP headers can be analyzed.

Approach

  • Read the CF-Connecting-IP header
  • Compare its value against a blacklist
  • Block the request if there is a match
  • Cache the result to improve performance

Note: Caching is critical, it avoids repeated disk access and reduces CPU usage significantly on high-traffic deployments.

Rule configuration

Below is the recommended configuration based on ModSecurity:

SecAction \
  "id:99295000,phase:1,pass,nolog,initcol:ip_cloudflare=%{REQUEST_HEADERS.CF-Connecting-IP}"

SecRule IP:is_bad "@eq 1" \
 "id:99295001,\
 phase:1,\
 deny,\
 status:403,\
 log,\
 t:none,\
 msg:'SKD Global: Blocked cached bad IP from CF-Connecting-IP'"

SecRule REQUEST_HEADERS:CF-Connecting-IP "@ipMatchFromFile /usr/local/skudonet/config/ipds/blacklists/lists/CIArmy.txt" \
  "id:99295002,phase:1,deny,status:403,log,t:none,msg:'SKD Global: Blocked blacklisted IP from CF-Connecting-IP',setvar:ip_cloudflare.is_bad=1,expirevar:ip_cloudflare.is_bad=3600"

Where to configure the rule

Navigate to:

Intrusion Prevention & Detection System → WAF → Files
  1. Create a new file
  2. Select type: Ruleset
  3. Add the configuration above

How the rule works

1. IP initialization

SecAction ...
  • Creates a persistent collection (ip_cloudflare)
  • Uses the CF-Connecting-IP as the key
  • Allows storing information per client

2. Cache-based blocking

SecRule IP:is_bad "@eq 1"
  • Checks whether the IP has already been marked as malicious
  • If so, it blocks immediately (HTTP 403)

Advantages

  • Avoids repeated file lookups
  • Reduces CPU and I/O usage
  • Improves response time

3. Blacklist comparison

SecRule REQUEST_HEADERS:CF-Connecting-IP "@ipMatchFromFile ..."
  • Reads the real client IP from the header
  • Compares it against the blacklist file

If there is a match:

  • The request is blocked
  • The IP is marked as malicious
  • It is cached for 1 hour

Variant: domain-based filtering (Host)

In multi-service environments, it may be useful to apply the blacklist only to specific domains.

Example

SecRule REQUEST_HEADERS:Host "@rx (?i)^portal\.domain\.com\.tr$"

Full example

SecAction \
"id:99295010,phase:1,pass,nolog,initcol:ip_cloudflare=%{REQUEST_HEADERS.CF-Connecting-IP}"

SecRule REQUEST_HEADERS:Host "@rx (?i)^portal\.domain\.com\.tr$" \
"id:99295011,phase:1,deny,status:403,log,t:none,msg:'SKD Global: Blocked cached bad IP for target host',chain"

SecRule IP:is_bad "@eq 1" \
"t:none"

SecRule REQUEST_HEADERS:CF-Connecting-IP "@ipMatchFromFile /usr/local/skudonet/config/ipds/blacklists/lists/CIArmy.txt" \
"id:99295012,phase:1,deny,status:403,log,t:none,msg:'SKD Global: Blocked blacklisted IP from CF-Connecting-IP for target host',chain"

SecRule REQUEST_HEADERS:Host "@rx (?i)^portal\.domain\.com\.tr$" \
"t:none,setvar:ip_cloudflare.is_bad=1,expirevar:ip_cloudflare.is_bad=3600"

This variant enables:

  • Apply rules only to a specific service
  • Avoid impacting other domains
  • Greater control in multi-tenant or reverse proxy environments

Best practices

When using Cloudflare in front of SKUDONET:

  • Allow only Cloudflare IPs at the network level
  • Use CF-Connecting-IP as the real client source
  • Apply blacklist filtering in the WAF (L7)
  • Implement caching to optimize performance

Advantages of this approach

  • Maintains protection against malicious IPs
  • Avoids blocking Cloudflare infrastructure
  • Compatible with existing blacklists
  • Scales well even with large lists
  • Reduces CPU usage thanks to in-memory caching

Related Articles

Download Skudonet ADC Load Balancer
Community Edition

Source Code

A versatile and installable ADC system designed for diverse vendor hardware.

DOWNLOAD SOURCE

Installable ISO 

Load Balancing as a Service alongside an ADC orchestration toolkit.

DOWNLOAD ISO