- Published on
Securing Pathao.com: A Deep Dive into Enterprise-Grade WordPress Security Implementation
- Authors
- Name
- Nadim Tuhin
- @nadimtuhin
Disclaimer: This blog post presents a significantly modified and simplified version of the actual security implementation. Many details have been intentionally altered or omitted for security reasons. The configurations shown are for educational purposes only and should not be considered a complete representation of the production environment.
Hey there! Today, I want to share how we secured Pathao.com, one of the largest ride-sharing platforms in South Asia. When you're serving millions of users across multiple countries, security isn't just a checkbox—it's a critical foundation of your infrastructure.
In this post, I'll walk you through our security implementation, from basic nginx configurations to advanced attack prevention. Whether you're running a WordPress site or any web application, you'll find practical security measures you can implement today.
The Challenge
Pathao.com runs on WordPress multisite, serving content in three languages:
- Main site (English):
/
- Bengali site:
/bn
- Nepali site:
/np
Each site needs its own security considerations while maintaining consistent protection across the platform. We faced several critical challenges:
High-Value Target: As one of South Asia's leading tech companies, we were constantly targeted by:
- Automated vulnerability scanners
- Malicious bots and crawlers
- SQL injection attempts
- Brute force login attacks
Performance Impact: Security scanning tools were causing:
- High server CPU usage from repeated scanning
- Increased bandwidth consumption
- Slower response times for legitimate users
- Occasional server timeouts during peak scan periods
Multilingual Complexity: Managing security across three different sites meant:
- More entry points to protect
- Complex URL patterns to secure
- Different content types requiring varied security rules
- Maintaining consistent security across all language variants
WordPress-Specific Vulnerabilities: Being on WordPress meant dealing with:
- Plugin security vulnerabilities
- Theme security issues
- Core WordPress exploits
- File upload vulnerabilities
Let's dive into how we tackled this!
Security Implementation
1. Security Headers
First, we implemented essential security headers to protect against common web vulnerabilities:
# Prevent version disclosure
server_tokens off;
# HSTS for enforcing HTTPS
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains;";
# Prevent clickjacking attacks
add_header X-Frame-Options SAMEORIGIN;
# Disable content-type sniffing
add_header X-Content-Type-Options nosniff;
# Enable XSS protection
add_header X-XSS-Protection "1; mode=block";
These headers form our first line of defense against various attack vectors.
2. Basic Security Measures
We implemented several fundamental security measures:
# Prevent directory listing
autoindex off;
# Block double slash in URLs
location ~* //wp-content {
return 403;
}
# Block hidden files (like .git, .htaccess)
location ~ /\. { deny all; }
# Handle favicon and robots.txt efficiently
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
try_files $uri /index.php?$args;
}
3. WordPress Core Protection
We implemented strict access controls for WordPress core files and functionality:
# Block XML-RPC access
location ~* "xmlrpc.php" { deny all; }
location ~* "readme.txt" { deny all; }
# Protect sensitive WordPress directories
location ~* wp-admin/includes { deny all; }
location ~* wp-includes/theme-compat/ { deny all; }
location ~* wp-includes/js/tinymce/langs/.*\.php { deny all; }
# Block access to configuration files
location ~ /(\.|wp-config.php|readme.html|license.txt) { deny all; }
# Block temp files
location ~ ~$ { access_log off; log_not_found off; deny all; }
# Block archive files
location ~* ^/(wp-content)/(.*?)\.(text|txt|zip|gz|tar|bzip2|7z)$ { deny all; }
4. Upload Directory Security
Comprehensive protection for upload directories:
# Block backup directories
location ~ ^/wp-content/uploads/sucuri { deny all; }
location ~ ^/wp-content/updraft { deny all; }
# Protect plugin/theme documentation
location ~* ^/wp-content/plugins/.+\.(txt|log|md)$ {
deny all;
error_page 403 =404 / ;
}
# Secure multisite uploads
location ~* ^/wp-content/uploads/sites/\d+/ {
try_files $uri $uri/ /index.php?$args;
location ~ \.php$ {
deny all;
}
}
# Block PHP execution in uploads
location ~* /wp-content/uploads/.*\.php$ {
deny all;
}
# Block restricted file types in uploads
location ~* ^/wp-content/uploads/.*.(html|htm|shtml|php|js|swf|css)$ {
add_header X-Block-Reason "Restricted Upload File Type" always;
deny all;
error_page 403 =404 / ;
}
5. Attack Prevention
SQL Injection Protection
# Block SQL injection attempts
location ~* "(\'|\")(.*)(drop|insert|md5|select|union)" {
add_header X-Block-Reason "SQL Injection Attempt" always;
deny all;
}
Path Traversal Prevention
# Block path traversal attempts
location ~ "(\\|\.\.\.|\.\./|~|`|<|>|\|)" {
add_header X-Block-Reason "Path Traversal" always;
deny all;
}
File Inclusion & CGI Protection
# Block sensitive file extensions
location ~* \.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$ {
add_header X-Block-Reason "Sensitive File Extension" always;
return 444;
}
# Block CGI execution
location ~* \.(pl|cgi|py|sh|lua)$ {
add_header X-Block-Reason "CGI/Script Execution Not Allowed" always;
return 444;
}
Documentation & Backup Protection
# Block access to documentation files
location ~* "/(^$|readme|license|example|README|LEGALNOTICE|INSTALLATION|CHANGELOG)\.(txt|html|md)" {
add_header X-Block-Reason "Documentation File Protected" always;
deny all;
}
# Block access to backup files
location ~* "\.(old|orig|original|php#|php~|php_bak|save|swo|aspx?|tpl|sh|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rdf)$" {
add_header X-Block-Reason "Backup/Log File Protected" always;
deny all;
}
XSS & Command Injection Protection
# Block XSS attempts
location ~* "(<|%3C).*script.*(>|%3)" {
add_header X-Block-Reason "XSS Attempt" always;
deny all;
}
# Block remote file inclusion attempts
location ~* "(https?|ftp|php):/" {
add_header X-Block-Reason "Remote File Inclusion Attempt" always;
deny all;
}
# Block command injection attempts
location ~ "(~|`|<|>|:|;|%|\\|\s|\{|\}|\[|\]|\|)" {
add_header X-Block-Reason "Command Injection Attempt" always;
deny all;
}
Performance Optimization
While security was our primary focus, we also implemented performance optimizations to ensure fast content delivery.
1. Direct Static File Serving
Instead of proxying to Apache, we serve static files directly through nginx for better performance:
# Multilingual static asset handling
location ~* ^/(bn|np)?/.*\.(jpg|jpeg|png|gif|ico|css|js|svg|woff2)$ {
access_log off;
expires max;
add_header Cache-Control "public, no-transform";
add_header X-Static-File "true";
try_files $uri $uri/ =404;
}
This configuration:
- Handles files for all language variants
- Implements aggressive caching
- Bypasses Apache completely for static content
- Reduces server load significantly
2. WordPress Content Optimization
We apply similar optimizations to WordPress content:
# WordPress content handling
location ~* ^/(bn|np)?/wp-content/ {
access_log off;
expires max;
add_header Cache-Control "public, no-transform";
add_header X-Static-File "true";
try_files $uri $uri/ =404;
}
Dealing with Bounty Hunters and Security Scanners
One of the biggest challenges we faced was the constant load from bounty hunters and automated security scanners. As a prominent tech company in South Asia, Pathao.com was a frequent target for:
- Bug bounty hunters running automated scans
- Security researchers testing for vulnerabilities
- Automated vulnerability scanners and bots
- Penetration testing tools running continuous scans
These activities were creating significant server load and occasionally impacting site performance. Our security implementations helped in several ways:
- Early Request Filtering: By blocking malicious patterns at the nginx level, we prevented these requests from reaching the application server
- Reduced Server Load: Security scanners often make thousands of requests testing for vulnerabilities - our rules block these at the edge
- Resource Protection: Rules preventing access to sensitive paths and files meant fewer server resources wasted on handling these requests
- Improved Response Times: By blocking known attack patterns early in the request cycle, we maintained better response times for real users
The implementation effectively created a robust shield, allowing legitimate traffic through while filtering out potentially harmful automated scans.
The Results
After implementing these security measures, we've seen:
- Zero Security Incidents: No successful attacks or breaches in production
- Better Performance: Our security layers actually helped improve site speed by blocking malicious requests early
- Lower Server Load: By blocking bad bots and attacks at the nginx level, we reduced unnecessary load on our application servers
- Improved SEO: Search engines love secure sites, and our security headers helped boost our rankings
The best part? These security measures are battle-tested in production, serving thousands of users daily. They're not just theoretical—they work.
Have you implemented similar security measures? Or do you have questions about any specific security rule? Let me know in the comments below!
Rate Limiting
To protect against abuse and DDoS attacks, we implemented comprehensive rate limiting:
# Define memory zones and rates for different request types
# Format: limit_req_zone $identifier zone=name:size rate=r/time_unit;
# General API requests
limit_req_zone $binary_remote_addr zone=general_api:10m rate=60r/m;
# Resource-intensive operations
limit_req_zone $binary_remote_addr zone=intensive_ops:10m rate=10r/m;
# Static file access
limit_req_zone $request_uri zone=static_files:10m rate=60r/s;
# Frontend requests
limit_req_zone $binary_remote_addr zone=frontend:10m rate=150r/m;
# Admin area requests
limit_req_zone $binary_remote_addr zone=admin:10m rate=600r/m;
This configuration demonstrates a tiered rate limiting approach:
- Low rate (10r/m) for resource-intensive operations
- Medium rate (60r/m) for general API endpoints
- High rate (150r/m) for frontend requests
- Very high rate (600r/m) for admin operations
- URI-based limiting (60r/s) for static resources
Apply these limits in your location blocks:
# Example: Applying rate limits to different endpoints
# Resource-intensive endpoint
location /api/resource-heavy {
limit_req zone=intensive_ops burst=5 nodelay;
# ... rest of your configuration
}
# General API endpoint
location /api/ {
limit_req zone=general_api burst=10 nodelay;
# ... rest of your configuration
}
# Admin area
location /wp-admin/ {
limit_req zone=admin burst=20 nodelay;
# ... rest of your configuration
}
Testing and Verification
Here's a template for testing your security implementation:
Basic Access Testing:
# Test homepage access curl -I https://your-domain.com/ # Test subsite access (if using multisite) curl -I https://your-domain.com/site1/ curl -I https://your-domain.com/site2/
Security Rule Testing:
# Test file execution protection curl -I "https://your-domain.com/wp-content/uploads/test.php" curl -I "https://your-domain.com/wp-content/themes/test.php" # Test SQL injection protection curl "https://your-domain.com/?id=1' OR '1'='1" curl "https://your-domain.com/?user=admin'--" # Test path traversal protection curl -I "https://your-domain.com/wp-content/plugins/../../../etc/passwd" # Test sensitive file protection curl -I "https://your-domain.com/wp-config.php" curl -I "https://your-domain.com/.env"
Rate Limit Testing:
# Function to test rate limits test_rate_limit() { local endpoint=$1 local requests=$2 local delay=${3:-0} echo "Testing rate limit for $endpoint" for i in $(seq 1 $requests); do curl -I "$endpoint" &>/dev/null echo -n "." sleep $delay done echo "Done!" # Final request to check if rate limit is triggered curl -I "$endpoint" } # Example usage: # test_rate_limit "https://your-domain.com/api/" 100 0.1 # test_rate_limit "https://your-domain.com/wp-admin/" 50 0.2
Bot Detection Testing:
# Test with different User-Agents curl -I -A "Googlebot/2.1 (+http://www.google.com/bot.html)" https://your-domain.com/ curl -I -A "facebookexternalhit/1.1" https://your-domain.com/ curl -I -A "Mozilla/5.0 (compatible; Bingbot/2.0)" https://your-domain.com/
Remember to:
- Replace
your-domain.com
with your actual domain - Adjust request numbers and delays based on your rate limits
- Test from different IP addresses to verify IP-based limits
- Run tests in a staging environment first
- Monitor logs while testing to verify proper blocking
Maintenance Best Practices
To keep our security implementation effective:
- Monitor Logs: Regularly check nginx error logs for blocked attempts
- Update Rules: Keep security rules current with new threat patterns
- Test After Updates: Verify security measures after WordPress core/plugin updates
- Review Rate Limits: Adjust rate limiting based on traffic patterns
- Audit Bot Access: Monitor and update bot detection patterns
These security measures have proven effective in production, protecting millions of users while maintaining high performance. Remember to adapt these configurations to your specific needs and regularly test their effectiveness.