本文档针对 WordPress 网站面临的暴力破解攻击,提供了 2025 年的最佳实践防御指南。攻击者通过自动化尝试用户名/密码组合来入侵,文档强调采用多层次防护策略,包括 WordPress 层面、服务器/代理/WAF 层面的措施,并推荐优先使用边缘防护以减轻服务器负载。
# Apache 示例:限制 IP 访问 wp-login.php
<Files "wp-login.php">
Require ip 203.0.113.15 203.0.113.16
</Files>
# Nginx 示例:速率限制登录和 XML-RPC
limit_req_zone $binary_remote_addr zone=logins:10m rate=10r/m;
location = /wp-login.php {
limit_req zone=logins burst=20 nodelay;
include fastcgi_params;
}
# Caddy 示例:基于 IP 限制访问 wp-login.php
@blacklist {
not client_ip forwarded 203.0.113.15 203.0.113.16
path /wp-login.php
}
respond @blacklist "Forbidden" 403 {
close
}
# Windows IIS 示例:通过 web.config 限制 wp-admin 访问
<location path="wp-admin">
<system.webServer>
<security>
<ipSecurity allowUnlisted="false">
<add ipAddress="203.0.113.15" allowed="true" />
<add ipAddress="203.0.113.16" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
</location>A brute force attack is the simplest way to break in: an attacker repeatedly tries username/password combinations until one works. Because these attempts are automated and often distributed (botnets), even unsuccessful attacks can overwhelm your site with requests.
This is not unique to WordPress—every web application that exposes a login surface can be targeted—but WordPress’s popularity makes it a common focus. The guidance below reflects current best practices for WordPress sites in 2025 and replaces older, more fragile techniques.
Tip: Obscuring the login URL can reduce noise but should not be your only defense.
WordPress shows a strength meter when changing passwords. Encourage unique, long passwords (or passphrases) and the use of password managers. Avoid dictionary words and personal info.
Enable 2FA for all administrators and privileged users using a reputable plugin or your identity provider (TOTP app, hardware key, SMS fallback). As of 2025, WordPress core does not ship 2FA; it must be added via a plugin or SSO/IdP.
Passkeys provide phishing‑resistant, passwordless login using platform authenticators (Face ID/Touch ID, Windows Hello, security keys). Add via a maintained plugin that supports WebAuthn/Passkeys and enroll at least two authenticators per admin.
For API access by trusted apps/services, use Application Passwords (introduced in WordPress 5.6). They scope access and can be revoked without changing your user password.
If your host/CDN doesn’t rate‑limit at the edge, a security plugin can throttle login attempts. Note that app‑level plugins still execute within PHP and thus consume some resources under heavy attack; prefer edge or server‑level throttling when possible.
xmlrpc.php is a frequent brute‑force target (especially the system.multicall method). If you don’t use XML‑RPC, disable it. If you do (e.g., Jetpack, mobile apps), restrict it (WAF rules) and rate‑limit aggressively.
These examples require server or proxy access and may vary by environment. Test in staging before applying to production.
Block or rate‑limit abusive login attempts (examples require appropriate modules such as mod_rewrite, mod_authz_host, or third‑party tools like ModSecurity or mod_evasive).
Deny by IP (Apache 2.4+):
# wp-login.php: allow specific IPs only
<Files "wp-login.php">
Require ip 203.0.113.15 203.0.113.16
</Files>
Send 401/403 to a static error page:
ErrorDocument 401 /401.html
ErrorDocument 403 /403.html
Consider ModSecurity rulesets (e.g., OWASP CRS) to detect and block brute‑force patterns at the server layer.
Rate‑limit login and XML‑RPC:
# Define a shared zone for rate limiting
limit_req_zone $binary_remote_addr zone=logins:10m rate=10r/m;
server {
# ...
location = /wp-login.php {
limit_req zone=logins burst=20 nodelay;
include fastcgi_params;
# pass to PHP-FPM or upstream as usual
}
location = /xmlrpc.php {
limit_req zone=logins burst=20 nodelay;
include fastcgi_params;
# pass to PHP-FPM or upstream as usual
}
}
Deny by IP:
location = /wp-login.php {
allow 203.0.113.15;
allow 203.0.113.16;
deny all;
# pass to PHP-FPM or upstream as usual
}
Custom error pages:
error_page 401 /401.html;
error_page 403 /403.html;
Password‑protect /wp-login.php with Basic Auth:
# Hash passwords first: `caddy hash-password`
basicauth /wp-login.php {
user1 JDJhJDEw$example-hash-value...
# add more users as needed (one per line)
}
Caddy requires hashed passwords in the Caddyfile.
Limit access to /wp-login.php by IP:
@blacklist {
not client_ip forwarded 203.0.113.15 203.0.113.16
path /wp-login.php
}
respond @blacklist "Forbidden" 403 {
close
}
Return 401 for /wp-admin/* and serve a custom error page:
@wpadmin path /wp-admin/*
respond @wpadmin "Unauthorized" 401
handle_errors {
@need401 status 401
rewrite @need401 /401.html
file_server
}
Deny “no‑referrer” POSTs to login/comments (optional, use with caution):
# Legitimate clients or privacy tools may omit Referer; test before enforcing.
@protected path_regexp protected (wp-comments-post|wp-login).php$
@no_referer {
not header Referer https://{host}*
method POST
}
abort @no_referer
Using
abortimmediately drops the connection, which is efficient for bots.
For more Caddy discussion and rationale, see: Using Caddy to deter brute force attacks in WordPress (community thread).
Restrict WP Admin by IP using web.config:
<location path="wp-admin">
<system.webServer>
<security>
<ipSecurity allowUnlisted="false">
<add ipAddress="203.0.113.15" allowed="true" />
<add ipAddress="203.0.113.16" allowed="true" />
</ipSecurity>
</security>
</system.webServer>
</location>
Custom 401 page:
<system.webServer>
<httpErrors errorMode="Custom">
<remove statusCode="401" />
<error statusCode="401" path="/401.html" responseMode="File" />
</httpErrors>
</system.webServer>
A managed WAF (Cloudflare, Sucuri, or your hosting provider) can:
– Filter known bad IPs and automated login attempts at the edge.
– Enforce bot management, challenge‑pages, and login‑specific rules.
– Apply rate limits to /wp-login.php and /xmlrpc.php globally.
– Add CAPTCHA/turnstile challenges for suspicious requests.
Advantage: traffic is blocked before reaching your server, preserving resources during high‑volume attacks.
admin. Create a separate admin account and demote or remove legacy users.Older guidance often recommended heavy .htaccess rewrites, country IP blocklists, or BasicAuth over the entire /wp-admin directory. Today these measures are either unreliable, break AJAX‑based plugins, or degrade user experience. Prefer edge‑level WAF, 2FA, passkeys, and targeted rate‑limiting instead. When you do apply server‑level blocks, scope them narrowly (e.g., /wp-login.php, /xmlrpc.php) and document exceptions your site needs (mobile apps, Jetpack, SSO).