Securing Wordpres – My personal view

WordPress Security: A Personal Perspective on a Complex and Often Misunderstood Problem

Securing WordPress is a topic surrounded by myths, oversimplifications, and false expectations. This article represents my personal view, based on hands-on experience with high-traffic WordPress installations, custom plugins, e-commerce environments, and real post-attack recoveries.
It isn’t a universal truth, nor the only correct approach — but rather an attempt to explain why securing WordPress is challenging, what actually matters, and why some methods work better than others.

The first thing to understand is that WordPress security is context-dependent. While the engine is the same everywhere, the security needs of a:

  • high-traffic blog,
  • WooCommerce store,
  • membership platform,
  • corporate intranet,
  • or heavily customized installation

…are completely different. Treating them the same way leads to poor results, overuse of heavy plugins, and false feelings of safety.

In many cases, security plugins designed to “patch all holes” introduce significant performance overhead — to the point where they become counterproductive. They inspect every request, perform heavy scans, log data in inefficient ways, or hook deeply into WordPress internals. Under high load, this creates more problems than it solves.

Real security begins long before WordPress starts executing.


Why Hardening Matters More Than Plugins

The most important phase in securing a WordPress site is server-level hardening — restricting what the application can do and where PHP is allowed to execute. Proper hardening reduces the attack surface from thousands of potential entry points to a handful of well-understood endpoints.

A crucial principle is:

“Only allow PHP execution where WordPress actually needs it.”

WordPress itself requires PHP mainly for:

  • core files,
  • active plugins,
  • active themes,
  • admin and login pages,
  • selected AJAX endpoints.

It does not need PHP execution in:

  • /wp-content/uploads/
  • old theme directories
  • backup folders
  • custom temporary directories
  • import/export folders
  • file cache directories

The single most effective hardening step is disabling PHP execution in directories where it has no business running. On Apache that’s usually a simple .htaccess:

Apache
<FilesMatch "\.ph(p[3-7]?|tml)$">
  Order Allow,Deny
  Deny from all
</FilesMatch>

On Nginx:

Nginx
location ~* \.php$ {
    deny all;
}

Blocking PHP there prevents entire classes of attacks — including many plugin-based zero-days that rely on uploading a malicious script.


Hardening is also about minimizing information leaks:

  • WordPress version,
  • PHP version,
  • server banner,
  • theme and plugin metadata.

Yes, remove Readme.html, disable wp-version-check, strip PHP and server headers, but don’t kid yourself: attackers don’t fingerprint; they just run the latest WPScan or a Nuclei template and fire away. These steps help only against completely unsophisticated actors and against accidental information leakage in custom code. Modern attackers use automated exploit packs targeting specific vulnerabilities regardless of version hints. Obfuscating these details is helpful mostly when working with custom, proprietary code. Even then, it is more obscurity than protection — but still worth doing as an additional layer.


XML-RPC – The Gift That Keeps on Giving (Pain)

XML-RPC is a legacy remote procedure call system introduced in WordPress 1.5 (2005) and kept for backward compatibility. It powers the old mobile apps, Jetpack, some off-site posting tools, and – most importantly – distributed brute-force and DDoS attacks.

In 2025 the official WordPress mobile apps no longer require it (they switched to the REST API years ago), and Jetpack has fallback mechanisms. That means on 95 % of modern installations you can safely disable it completely.

Ways to disable XML-RPC:

  • Nginx: location = /xmlrpc.php { deny all; }
  • Apache: simple redirect or 403 in .htaccess
  • Cloudflare: Page Rule /xmlrpc.phpBlock
  • Plugin (only if you really need selective access): “Disable XML-RPC” or similar – but again, avoid PHP-level solutions on busy sites.

If you still need it (very rare), at least rate-limit it aggressively at the reverse-proxy level.

1. Brute-force attacks

XML-RPC allows multiple login attempts in a single request via system.multicall, making brute-forcing highly efficient.

2. DDoS amplification

Because it handles multiple operations at once, attackers can abuse it to generate significant server load.

3. Automated exploit scanning

Bots constantly probe the XML-RPC endpoint, looking for:

  • open pingbacks,
  • vulnerable plugins connected to XML-RPC,
  • misconfigurations.

If your site does not explicitly require XML-RPC, you should disable it — and not via a plugin, but at the web server level. However, this depends on your environment.

Still, in most modern setups, disabling it is both safe and beneficial.


Why Blocking Malicious Requests Inside WordPress Is Inefficient

Most security plugins proudly announce: “We blocked 1,247,893 attacks this month!” What they don’t tell you is that every single one of those requests still:

  • hit your web server
  • triggered PHP
  • loaded WordPress
  • consumed memory and CPU

That is unacceptable on a site doing >100 RPM.

A common mistake is relying solely on WordPress plugins to block attacks.
This approach is fundamentally flawed because:

  1. The web server handles the request first.
  2. PHP is invoked before the plugin does anything.
  3. Memory, CPU, and process slots are consumed.
  4. Only then the security plugin decides to block the request.

In high-traffic environments, this is simply too late.

Imagine stopping a burglar after they’ve already entered the house, walked to the kitchen, opened the fridge, and then you tell them “you’re not allowed here”. They still consumed your resources.

The better strategy is to block the attacker before they reach the front door:

Layer 1: Web Server-Level Blocking

  • Apache: mod_security, rewrite rules, .htaccess
  • Nginx: deny, rate limits, location blocks
  • Lighttpd: URL deny patterns

These rules prevent PHP from being triggered at all — saving CPU, memory, and request slots.

Layer 2: Reverse Proxy or Cloud-Level Protection

A layer above the server is even more effective:

  • Cloudflare
  • Fastly
  • Sucuri
  • Cloud-based WAFs

These systems block traffic before it reaches your server, stopping:

  • botnets,
  • exploit scanners,
  • brute-force attempts,
  • abusive crawlers,
  • DDoS floods.

For large WordPress sites, this often makes the difference between stable performance and daily outages.

The correct order of operations (from fastest to slowest):

  1. DNS-level filtering (Cloudflare Bot Fight Mode, BunnyCDN WAF, etc.)
  2. Reverse-proxy / WAF (Cloudflare Workers, Fastly VCL, Nginx + ModSecurity/Lua, AWS WAF, etc.)
  3. Web-server level (Fail2ban, Nginx deny lists, Apache mod_evasive)
  4. Only as last resort – PHP-level (i.e. security plugins)

Every request you stop at layer 1 or 2 saves you orders of magnitude of resources compared to layer 4.


Login Protection: The Most Targeted Endpoint of All

The WordPress login form (wp-login.php) is constantly targeted. Even small sites receive thousands of automated attempts daily.

The best defense is a combination of measures:

1. CAPTCHA or reCAPTCHA

For customer-facing login pages, such as WooCommerce stores, an invisible reCAPTCHA (v3) offers frictionless security.

2. Two-Factor Authentication (2FA)

Ideal for administrators, editors, and internal users.
It prevents 99% of account-based attacks.

3. An Additional Server-Level Password (HTTP Auth)

When a large editorial team cannot easily enforce 2FA, you can put an extra server-level password in front of the login form.
This means attackers must first pass the server-side authentication before even reaching WordPress.

It’s simple, elegant, and extremely effective at reducing load.


You Got Hacked – Now What? (The Checklist Nobody Wants to Run)

This section does not explain how to analyze a specific exploit — there are hundreds of them, each with unique traces. Instead, let’s focus on what must be done once the incident is contained and the malicious code removed.

Assume the worst has happened. The attacker is gone (you hope). Now you have to clean up without creating new problems.

Post-Hack Recovery Checklist

1. Regenerate all WordPress secret keys
These keys control session tokens and cookie authentication.
Regenerating them invalidates existing sessions — including those stolen by attackers.

2. Change the database password
The attacker may have had access to wp-config.php.

3. Update FTP/SFTP credentials
If FTP is still used (it shouldn’t be), assume compromise.

4. Update SSH passwords or replace SSH keys
If SSH keys were on the server, replace them — not just remove them.

5. Reinstall all plugins and themes from clean sources
A hacked file inside a plugin directory is extremely common.

6. Reinstall WordPress core files
This ensures no backdoors remain in core components.

7. Reset all user passwords
This step is painful for customer-facing sites, but necessary.
Honesty is important. Silence after a breach is worse than inconvenience.

Cleaning up after an attack is as much technical work as it is responsibility toward users.


Updates: Why They Are Difficult and How to Do Them Safely

Updating WordPress is often portrayed as just click the button.
In reality, professional installations rarely work this way.

Most production sites are Frankenstein monsters of 50+ plugins from 30 different vendors. One minor version bump can break everything.

My rule:

“Never run automatic updates on anything except tiny brochure sites.”

Real-world WordPress sites rely on: dozens of plugins, multiple themes, custom code,integrations with external systems. Each of these evolves independently. Updating WordPress core or a major plugin can easily break functionality.

That’s why automatic updates are dangerous in complex environments.

The Proper Update Workflow

A staging environment is what keeps WordPress in good shape and our nerves under control. It’s the safe space where updates can fail, plugins can conflict, and experiments can break without causing real-world damage. And the closer this environment is to production — in data, configuration, and infrastructure — the better it does its job. The more accurately it mirrors the live site, the more issues it catches early, long before they have a chance to disrupt users or our peace of mind.

1. Always maintain a separate staging/test environment
It should mirror production as closely as possible.

2. Sync production database and files to staging
Ensure no emails or payments go out accidentally. Check your configuration of the plugins and connection to database. This is a hard part and it’s offten ommited.

3. Perform updates on staging first
Here you discover:

  • fatal errors,
  • outdated plugins,
  • PHP incompatibilities,
  • broken templates,
  • conflicts between plugins.

4. Run complete testing scenarios
For e-commerce:

  • product creation
  • checkout
  • payment
  • email notifications

For content-heavy sites:

  • editor workflow
  • media uploads
  • plugin interactions

Or any other custom scenarios it’s good to have and check.

5. Only after full validation — update production
If staging fails, you fix the issue without pressure or downtime on the live site.

This process prevents outages that could cost money, reputation, or both.

Now, you can clik the button!


Conclusion

There is no silver bullet. WordPress security in 2025 is a moving target – new zero-days appear, plugins get abandoned, hosting environments change.

The strategies above – hardcore server-level hardening, killing XML-RPC, moving protection as far away from PHP as possible, aggressive login protection, and a paranoid update process – consistently delivered the best results for me on sites doing anywhere from 500k to 30 million pageviews per month.

Stay paranoid, test everything in staging, and never trust a plugin that promises to “secure WordPress with one click”.

Your future self (and your visitors) will thank you

Leave a Reply

Your email address will not be published. Required fields are marked *