Cloudflare WAF (Web Application Firewall)

Securing Web Applications

with Cloudflare WAF

– Mayank Gupta

Importance of web application security

  1. Protection of Sensitive Data
  2. Prevention of Cyber Attacks
  3. Maintaining User Trust
  4. Compliance with Regulations
  5. Business Continuity
  6. Preventing Financial Loss
  7. Protection Against Reputation Damage

Key features of Cloudflare WAF

  • Cloudflare WAF is a web application firewall service provided by Cloudflare.
  • Its primary purpose is to protect web applications from various online threats, including OWASP top 10 vulnerabilities.
  1. Enhanced Security: Protects against a wide range of web application attacks.
  2. Ease of Use: Easy to set up and manage through the Cloudflare dashboard.
  3. Cost-Effective: Provides robust security without the need for extensive infrastructure investments.
  4. Threat Detection: Real-time identification and blocking of malicious traffic.
  5. Bot Protection: Differentiate between human and bot traffic to mitigate automated attacks.
  6. Custom Rules: Ability to create and enforce custom security rules tailored to specific needs.
  7. Rate Limiting: Control the rate of requests to prevent abuse and DDoS attacks.

Cloudflare WAF Plan Comparison

Features Free Pro Business Enterprise
Number of custom CloudFlare firewall rules 5 20 100 1000
Support for regular expressions No No Yes Yes

Due to it’s popularity, WordPress is the most sought after target for most of the hackers.

  1. According to WordFence, around 90,000 attacks target a WordPress website every minute.
  2. A weak password is a culprit in 8% of the hacked WordPress sites.
  3. Around 4,000 WordPress websites are infected from malware present in fake SEO plugins.
  4. 61% of attacked websites are outdated.
  5. The four leading causes of WordPress vulnerabilities include Plugins (52%), Cross-site scripting issues (39%), Core files (37%), and Themes (11%).
  6. According to report by Sucuri, WordPress is 90% more likely to be hacked compared to other CMS.

Source: WP Clipboard

Block rule for WordPress sites

if incoming requests match…

(http.request.uri contains "/wp-admin/admin-ajax.php" and not http.referer contains "yourwebsite.com") 
or (http.request.uri contains "/xmlrpc.php" and not http.referer contains "yourwebsite.com") 
or (http.request.uri contains "/wp-login.php" and ip.geoip.country ne "US") 
or (http.request.uri contains "author") 
or (http.request.uri.path contains "/wp-includes" and not http.referer contains "yourwebsite.com" and not http.cookie contains "wordpress_logged_in") 
or (http.request.uri.path contains "/wp-admin" and not http.referer contains "yourwebsite.com" and not http.cookie contains "wordpress_logged_in") 
or (http.request.uri.path contains "wp-json" and not http.cookie contains "wordpress_logged_in") 
or (http.request.method eq "POST" and ip.geoip.country ne "US" and not http.cookie contains "wordpress_logged_in") 

Then Block!

IMPORTANT NOTES
  1. It’s important to note that these rules will make WordPress secure, but it may break some of the functionality that your site requires. If that’s the case, you’ll have to tune these rules according to your requirements.
  2. Don’t forget to TEST as much as you can. These rules have the potential to impact SEO of the site as well.
  3. Refer to Cloudflare WAF Docs and refer to the explanation of the above rules in next slides.
(http.request.uri contains "/wp-admin/admin-ajax.php" and not http.referer contains "yourwebsite.com") 
or (http.request.uri contains "/xmlrpc.php" and not http.referer contains "yourwebsite.com") 
or (http.request.uri contains "/wp-login.php" and ip.geoip.country ne "US") 
or (http.request.uri contains "author") 
or (http.request.uri.path contains "/wp-includes" and not http.referer contains "yourwebsite.com" and not http.cookie contains "wordpress_logged_in") 
or (http.request.uri.path contains "/wp-admin" and not http.referer contains "yourwebsite.com" and not http.cookie contains "wordpress_logged_in") 
or (http.request.uri.path contains "wp-json" and not http.cookie contains "wordpress_logged_in") 
or (http.request.method eq "POST" and ip.geoip.country ne "US" and not http.cookie contains "wordpress_logged_in") 
  1. Chain the rules using And and OR to avoid creating multiple custom rules
  2. Will block requests directly made to URLs when /wp-admin/admin-ajax.php, /wp-login.php, /xmlrpc.php or author is in the path.
  3. and not http.referer contains "yourwebsite.com" Will ensure that it’ll not block requests generated by WordPress themes & plugins to these URLs.
  4. It’ll block any requests where the path contains author in the URL to avoid user enumeration.
  5. ne "US" will also ensure that the requests from any country other than United States will be blocked.
  6. You can modify the country or add more countries by adding and ip.geoip.country ne "IN" right after “US” and before closing bracket.
(http.request.uri contains "/wp-admin/admin-ajax.php" and not http.referer contains "yourwebsite.com") 
or (http.request.uri contains "/xmlrpc.php" and not http.referer contains "yourwebsite.com") 
or (http.request.uri contains "/wp-login.php" and ip.geoip.country ne "US") 
or (http.request.uri contains "author") 
or (http.request.uri.path contains "/wp-includes" and not http.referer contains "yourwebsite.com" and not http.cookie contains "wordpress_logged_in") 
or (http.request.uri.path contains "/wp-admin" and not http.referer contains "yourwebsite.com" and not http.cookie contains "wordpress_logged_in") 
or (http.request.uri.path contains "wp-json" and not http.cookie contains "wordpress_logged_in") 
or (http.request.method eq "POST" and ip.geoip.country ne "US" and not http.cookie contains "wordpress_logged_in") 
  1. http.request.uri.path is similar to the rule http.request.uri as explained earlier.
  2. not http.cookie contains "wordpress_logged_in" means don’t block the request when wordpress_logged_in cookie is set.
  3. You may have a different cookie for when you are logged in.
  4. Please check the instructions here on how to detect cookies for a logged in user.
  5. IMPORTANT We need to ensure that you choose the cookie that is set only when the user is logged in, to avoid blocking requests for logged in users.
(http.request.uri contains "/wp-admin/admin-ajax.php" and not http.referer contains "yourwebsite.com") 
or (http.request.uri contains "/xmlrpc.php" and not http.referer contains "yourwebsite.com") 
or (http.request.uri contains "/wp-login.php" and ip.geoip.country ne "US") 
or (http.request.uri contains "author") 
or (http.request.uri.path contains "/wp-includes" and not http.referer contains "yourwebsite.com" and not http.cookie contains "wordpress_logged_in") 
or (http.request.uri.path contains "/wp-admin" and not http.referer contains "yourwebsite.com" and not http.cookie contains "wordpress_logged_in") 
or (http.request.uri.path contains "wp-json" and not http.cookie contains "wordpress_logged_in") 
or (http.request.method eq "POST" and ip.geoip.country ne "US" and not http.cookie contains "wordpress_logged_in") 
  1. http.request.method eq "POST" ensures that any POST requests (used to fill out forms or send data to the server) are blocked.
  2. These POST requests are only allowed from US and not any other country
  3. And aren’t blocked if the user is logged in.
  4. Ensures that WordPress backend opearations run without any issues.
  5. NOTE In frontend, no form will be filled though.
  6. You can always add and not http.request.uri.path contains "/contact" to chain in line 8 to allow any contact form submissions.
  7. You’ll also have to modify to allow comment form submissions on blog posts.

Skip rule if incoming requests match…

(cf.client.bot) 
or (ip.src eq xx.xx.xx.xx) 
or (http.request.uri.query contains "AnySecretQueryString") 

Skip known bots

(cf.client.bot) 
or (ip.src eq xx.xx.xx.xx) 
or (http.request.uri.query contains "AnySecretQueryString") 
  1. This rule is used to ensure that any requests by known bots by Cloudflare are skipped and aren’t blocked.
  2. Very much required to ensure that SEO bots aren’t blocked and it doesn’t impact the SEO

Skip requests for specific IP(s)

(cf.client.bot) 
or (ip.src eq xx.xx.xx.xx) 
or (http.request.uri.query contains "AnySecretQueryString") 
  1. If you want to allow a particular IP by default then you can add various IPs
  2. You can also use IP Range here
  3. or you can also use custom lists

Skip requests for a specific query string

(cf.client.bot) 
or (ip.src eq xx.xx.xx.xx) 
or (http.request.uri.query contains "AnySecretQueryString") 
  1. This is optional but can be setup to test when the user is not logged in.
  2. Can be helpful in testing

Thank You