| 开发者 | wpformation |
|---|---|
| 更新时间 | 2026年5月11日 23:47 |
| 捐献地址: | 去捐款 |
| PHP版本: | 8.1 及以上 |
| WordPress版本: | 6.9 |
| 版权: | GPLv2 or later |
| 版权网址: | 版权信息 |
wp-login.php with a custom slug. Anyone hitting the old URL gets a 404 from your theme - no leakage that WordPress is even installed. Compatible with multisite, password-protected posts, reverse proxies, and password recovery flows. The branded pre-activation modal lets you pick or generate the slug before flipping the switch, and emails it to you so you can't lock yourself out.
2. Brute Force Protection - Cascading lockouts after repeated failed logins. Locked attackers see a branded 429 landing page with a live countdown. Repeated lockouts escalate to a 24-hour ban. Lostpassword, register, XML-RPC and the REST users endpoint are all gated when an IP is locked, so attackers can't pivot. Subnet blocking handles distributed attacks. Trusted X-Forwarded-For for sites behind Cloudflare or a load balancer.
3. Hardening - Thirteen one-click toggles across surface reduction, credential hardening, and request filtering. Disable XML-RPC, the theme/plugin file editor, the WordPress version exposure (including ?ver= on assets, even for WP 6.5+ ES modules), application passwords, author enumeration, and more. Block reserved usernames with Unicode-confusable detection. Add an invisible login honeypot. Block PHP execution in uploads and directory listing via atomic-write .htaccess rules.
4. Two-Factor Authentication - Enterprise-grade 2FA in three flavours: TOTP via any authenticator app (Google Authenticator, Authy, 1Password, Bitwarden), one-time codes by email, and printable backup codes. Trusted devices remembered for thirty days so you only verify once per browser. A recovery flow lets a user reset their second factor by email when the authenticator is lost, without a support ticket. Per-role enforcement, configurable grace period, and a session-aware logout.
5. Detection and Incidents - A real-time detection engine groups raw events into six attack patterns: brute force, credential stuffing, distributed scan, post-compromise activity, lockout cascade, and protocol abuse. Each incident has a drill-down view with timeline, source IPs, target users, severity, user-agent fingerprint, and one-click resolution actions (reset password, block subnet, mark resolved).
6. Activity Log - Compliance-ready audit trail of admin actions: plugin installs, settings changes, role updates, user creation, content publishing, theme switches, 2FA enrollment events. Filter, search and export to CSV with configurable retention. Seven logger domains, all togglable independently.
7. Login Page Security Headers - Content-Security-Policy, X-Frame-Options, Permissions-Policy, Referrer-Policy and X-Content-Type-Options on wp-login.php and the lockout page. Two presets (standard and strict) with an optional CSP report-uri.
8. Breach Check - Detect users logging in with a password that appears in public data breach corpora, using privacy-preserving k-anonymity lookups against Have I Been Pwned. Only the first 5 hex characters of a SHA-1 prefix leave the server, the password and full hash never travel. Optional opt-in email lookup against XposedOrNot. Fail-soft: a HIBP outage never blocks login.
Plus
wp login-armor reset-slug, unblock, whitelist, incidents resolve, purge-logs, 2fa reset, 2fa devices, hardening blacklist. Full scripted operations and emergency recovery from the shell.wp-login.php par une URL personnalisee. Toute tentative sur l'ancienne URL renvoie une 404 du theme, sans reveler la presence de WordPress. Compatible multisite, articles proteges par mot de passe, reverse proxies, et flux de recuperation de mot de passe. La modale de pre-activation vous laisse choisir ou generer le slug avant d'activer le module, et vous l'envoie par e-mail pour eviter tout verrouillage.
2. Protection contre la force brute : verrouillages en cascade apres plusieurs echecs. Les attaquants verrouilles voient une page 429 brandee avec un compte a rebours en direct. Les verrouillages repetes montent a un bannissement de 24 h. Les pages lostpassword, register, XML-RPC et l'endpoint REST users sont egalement bloques pour les IPs verrouillees, pour empecher le pivot. Blocage de sous-reseaux pour les attaques distribuees. Support de X-Forwarded-For pour les sites derriere Cloudflare ou un load balancer.
3. Renforcement : treize bascules en un clic, regroupees en reduction de surface, durcissement des identifiants et filtrage des requetes. Desactivation de XML-RPC, de l'editeur de fichiers theme/extension, de l'exposition de la version WordPress (y compris le ?ver= sur les assets, meme les modules ES de WP 6.5+), des mots de passe applicatifs, de l'enumeration des auteurs. Blocage des identifiants reserves avec detection des homoglyphes Unicode. Pot de miel invisible sur le formulaire de connexion. Blocage de l'execution PHP dans wp-content/uploads/ et desactivation du listing de repertoires via des regles .htaccess ecrites en mode atomique.
4. Authentification a deux facteurs : 2FA prete pour la production avec trois methodes : TOTP via n'importe quelle application authenticator (Google Authenticator, Authy, 1Password, Bitwarden), codes a usage unique par e-mail, codes de secours imprimables. Appareils de confiance memorises pendant trente jours, vous ne validez qu'une fois par navigateur. Une procedure de recuperation laisse l'utilisateur reinitialiser son second facteur par e-mail en cas de perte, sans ouvrir de ticket. Application par role, periode de grace configurable, et deconnexion qui ferme proprement les sessions actives.
5. Detection et incidents : un moteur en temps reel regroupe les evenements bruts en six patterns d'attaque : force brute, credential stuffing, scan distribue, activite post-compromission, cascade de verrouillages et abus protocolaires. Chaque incident dispose d'une vue detaillee : chronologie, IPs sources, comptes cibles, severite, empreinte user-agent et actions de resolution en un clic (reinitialisation de mot de passe, blocage de sous-reseau, marquage resolu).
6. Journal d'activite : piste d'audit conforme des actions admin : installations d'extensions, modifications de reglages, changements de role, creations d'utilisateurs, publications de contenu, changements de theme, evenements 2FA. Filtrage, recherche et export CSV avec retention configurable. Sept domaines de loggers, activables independamment.
7. En-tetes de securite de la page de connexion : Content-Security-Policy, X-Frame-Options, Permissions-Policy, Referrer-Policy et X-Content-Type-Options sur wp-login.php et la page de verrouillage. Deux presets (standard et strict) avec une option de CSP report-uri.
8. Detection de fuites : repere les utilisateurs qui se connectent avec un mot de passe present dans des fuites publiques, via des recherches preservant la vie privee (k-anonymat) sur Have I Been Pwned. Seuls les 5 premiers caracteres hexa d'un prefixe SHA-1 quittent votre serveur ; le mot de passe et le hachage complet ne sortent jamais. Verification e-mail optionnelle (opt-in, desactivee par defaut) via XposedOrNot. Fail-soft : une coupure de HIBP ne bloque jamais la connexion.
En plus
wp login-armor reset-slug, unblock, whitelist, incidents resolve, purge-logs, 2fa reset, 2fa devices, hardening blacklist. Operations scriptees et recuperation d'urgence depuis la ligne de commande.login-armor directory to /wp-content/plugins/my-login)login_armor_hide_slug row from the wp_options tablewp option delete login_armor_hide_slugNo. Hide Login always sends a one-time recovery URL to the admin email. If you lose the slug, check your inbox. The plugin also honors wp-cli fallback so you can reset anything from SSH.
No. Everything is lazy-loaded and indexed. On a normal login flow the extra SQL cost is under 2 ms.
Yes. IP detection honors trusted X-Forwarded-For headers; you pick the header in Settings.
Yes, subdomain and subfolder. Each site has its own modules, logs, and thresholds.
Yes, but disable overlapping modules on one side to avoid double lockouts.
Three custom tables in your own database: events, incidents, activity. Nothing leaves your server.
Settings are plain WordPress options. Export/import via WP-CLI or any standard options-sync tool.
Not currently. LoginArmor is fully free and open source. GPL forever.
Support forum: wordpress.org/support/plugin/login-armor/.
/%postname%). With 2FA enabled, the verification challenge after submitting login credentials would disappear and the user would land back on the login form with no error message. Reported by a user on 2026-05-11.
PendingCookie::get_path() no longer appends a trailing slash to the Hide Login slug. The cookie was set with path /<slug>/, but the trailing-slash normalisation in HideLogin::handle_loaded() would 302 the verify URL to /<slug>?login-armor-2fa=verify (no trailing slash) on installs where permalink_structure does not end with /. RFC 6265 §5.1.4 path-match then refused to send the cookie on /<slug> because the cookie path /<slug>/ is strictly longer than the request path. maybe_render_verification saw token_data === false and silently bounced to the login URL — exactly the "stuck on login page, no error" symptom. Setting the cookie path to /<slug> (no trailing slash) matches /<slug>, /<slug>/, and /<slug>/... per RFC 6265 while still rejecting /<slug>XYZ.www hostnames route to the same WordPress without a server-level canonical 301 (common on shared hosting). Two complementary fixes.
HideLogin::intercept_request() now canonicalises the request host before any URI rewriting. If the request lands on a hostname that matches neither home_url() nor site_url() (e.g. example.com/<slug> when siteurl is https://www.example.com), Hide Login issues a 301 to the canonical host preserving the full request URI. Closes the window where WP core's redirect_canonical (which runs later on template_redirect) was being short-circuited by Hide Login's plugins_loaded priority 9999 interception. Host-only comparison (not scheme/port) to avoid loop-redirects on misconfigured reverse-proxy setups. Skips WP-CLI, cron and AJAX defensively.LoginHeaders::build_csp() is now host-aware. Every CSP directive that governs cross-origin resource loads (script-src, style-src, img-src, font-src strict mode, connect-src strict mode, default-src strict mode, form-action) emits 'self' PLUS the parsed origins of home_url() AND site_url(). Without this, the previous 'self'-only policy blocked every wp_enqueue_style()-emitted CSS link whenever the document host differed from the asset host. Defence-in-depth alongside the canonical-host fix. base-uri stays 'self' — cross-origin <base> is always a security hole.login_armor_canonical_host_redirect to skip the V2.1.12 canonical-host 301 when returning false (proxy setups, dev environments, multisite configs with a third routing hostname). Receives $http_host, $home_host, $site_host.home_url() and site_url() resolve to the same single canonical host. Bug reported by Alexandre Puy on dumouriez.com (Dynamixhost / Apache / Debian).HideLogin::build_login_url() is now host-aware: chooses between home_url() and site_url() based on the request's HTTP_HOST header, instead of always returning site_url() (V2.1.9/V2.1.10 default). Resolves the case where a subsite mapped on an external domain would redirect immediately to /wp-admin/ (404) when typing the slug, because site_url() pointed to the original network path while the request arrived on the mapped domain. Reported on the WP.org support forum by @graphandco. Standard installs (siteurl == home) and multisite headless setups (where the request arrives on the siteurl host) continue to work as in V2.1.9/V2.1.10.intercept_request() now matches against BOTH home_url($slug, 'relative') AND site_url($slug, 'relative') (instead of just one). Same dual-base matching extended to the wp-login.php and wp-register.php traps. No security change: relative paths only, no new hostnames accepted.login_armor_login_url_base (introduced in V2.1.9) is unchanged and continues to wrap the final URL for advanced overrides (third-host scenarios, custom subdomain mapping plugins)./wp-admin/ with Hide Login enabled now renders as a proper WordPress 404 instead of a half-bootstrapped theme page with a duplicated header.
block_access() now routes through serve_404_template() so the response carries the proper WP_Query::set_404() state. Visible effect: body class error404 is set, Yoast (or any SEO plugin) emits <meta name="robots" content="noindex">, the theme renders its real 404 template instead of a default page layout, and themes with sticky headers (Astra Pro, many FSE themes) no longer show a duplicated header. No security change, no functional change for the actual 404 status header (still 404).block_access(); both code paths now share serve_404_template().site_url() instead of home_url() to build the rewritten login URL, matching what WordPress core does inside wp_login_url().
home_url() to site_url() (14 callsites migrated to a new public static helper HideLogin::build_login_url()). Inherited from the WPS Hide Login fork, the previous home_url() base was invisible on the ~99 percent of installs where siteurl == home, but broke silently on multisite headless (siteurl on admin.example.com, home on example.com), WordPress installed in a subdirectory (/wp/), and reverse-proxy installs with WP_HOME not equal to WP_SITEURL. Reported on the WP.org support forum by @graphandco.login_armor_login_url_base for exotic setups where neither home_url() nor site_url() matches the hostname that actually serves the login slug (third hostname behind a reverse-proxy, subdomain mapping plugin rewriting the admin URL, etc.). Receives $url, $path, $scheme, $slug.siteurl == home. Fresh-install, multisite-headless and WP-in-subdir validation suite passed before tag.admin/views/tabs/settings.php queries the V2.1.1 webhook queue table without an existence guard. On a fresh install where the Activity Log module was never enabled (table not created) or after wp plugin install --force (which doesn't re-fire activation), every Settings tab load emitted three DB warnings in debug.log (Table 'X.wp_login_armor_webhook_queue' doesn't exist). Non-fatal but log-polluting. Now wraps the SELECT in a SHOW TABLES LIKE guard and returns zero counts when the table is absent.uninstall.php cleanup list was missing the login_armor_lockout_window option (default 24h, used by LimitLogin::trigger_lockout() for escalation tracking). Plugin deletion previously left this single option behind. Now: zero residue.wp i18n make-pot regen: the V2.1.1 Activity Log integrity badge BROKEN, the legacy-rows-not-covered amber notice (singular form), the Breach Check password-found message (singular), the Breach Check email-breach message (singular), and the plugin description meta. All translated to French in languages/login-armor-fr_FR.po, no em dash. .mo recompiled. .pot regenerated against the full source tree (1010 strings vs 990 in 2.1.7) to capture 20 strings that had been added to the code (V2.1.1 webhook + integrity UI) but never made it into the translation template.wp_mail() fails. The login_armor_2fa_method = email user meta was previously written before the verification email was attempted, leaving a partially configured state behind on hosts where SMTP is broken (Wanadoo, mutualised hosts without SMTP relay, etc.). The order is now: send first, persist only on success.wp_mail() round-trip with a Send-test-email button and a safety-net checkbox ("I have a second admin tab open") before the Enable button unlocks. Both gates must pass, eliminating the most common cause of admin-locked-out support tickets.login_armor_2fa_email_test (nonce-protected) sends a one-shot test message without consuming the OTP cooldown.register() still gated by the enable option — zero-overhead contract preserved.uninstall.php now drops the V2.1.1 webhook queue table, deletes 14 leftover options (HSTS, login headers preset, activity auto-verify daily, V2.1.1 chain init flag + show-notice, 5 webhook), generalizes the transient SQL DELETE to login_armor_* (covering chain_verify_last and any future transient), and clears 3 V2.1.1 cron hooks (webhook dispatch + chain repair + chain auto-verify). Plugin deletion now leaves zero residual data.Class "LoginArmor\ActivityLog\ActivityLog" not found on every fresh install. The class file was loaded only when the Activity Log module was enabled, but the V2.1.1 chain initializer hooked at init priority 5 references the class unconditionally. On a fresh install (Activity Log option not yet set), every request to wp-login.php and the front end crashed with a 500. Existing sites that already had Activity Log enabled were unaffected. Fixed by always loading the class file (constructor still gated — zero-overhead contract preserved) and adding a defensive class_exists guard at the top of maybe_initialize_activity_chain().?ver= cache-buster from LoginArmor's own admin assets (admin.css, admin.js), in addition to WP core and 3rd-party plugin files. Combined with hosting providers that run a server-side static cache (LiteSpeed LSADC on o2switch PowerBoost, Cloudflare full-page cache, hosting CDNs) keyed on the canonical URL, every LoginArmor update past 2.1.0 was invisible to admins for up to a year of cache TTL — the browser kept fetching the old admin.css from the server-side cache because admin.css (no query) and admin.css?ver=2.1.2 are different cache keys. Filter now whitelists /plugins/login-armor/ paths so our own assets always carry their version-derived hash, while WP core and 3rd-party version disclosure are still stripped.width="18" height="18" HTML attributes on the Activity Log Integrity bar's shield SVG icon. Without these, if admin.css fails to reach the browser for any reason (CDN edge stale cache, content-blocker, proxy stripping CSS), the icon defaults to its intrinsic 300x150px and dominates the page layout. The CSS rule is still authoritative; HTML attrs are belt-and-suspenders.LoginArmor\ActivityLog\WebhookDispatcher was referenced in the Settings tab without an explicit require_once, and the file is only loaded when Activity Log is on. Visiting the Settings tab on a default install crashed with Class "LoginArmor\ActivityLog\WebhookDispatcher" not found. Fixed by loading the file unconditionally before its first use.Settings saved.) was anchored top-right and overlapped the LoginArmor admin tabs nav, making the message unreadable behind the dark Réglages tab. Moved to bottom-right (Gutenberg snackbar convention), bumped z-index above sticky elements, and re-tuned the entrance animation to slide up from the bottom edge.X-LoginArmor-Signature HMAC header, adaptive retry policy, max 5 attempts.wp login-armor activity verify-chain for scheduled audits and orphan repair (--from, --to, --repair-orphans, --format, --verbose).login_armor_rest_public_namespaces; auto-detection of 6 conflicting Hide Login plugins (Rename wp-login.php, WPS Hide Login, Defender, Solid Security, Wordfence, AIOS).mask_login_errors no longer leaks remaining-attempt hint through LimitLogin filter (S-9), Honeypot switched to <input type="hidden"> to survive theme stripping (S-22), User-Agent truncation cap reduced 500 -> 256 chars (S-19).wp_salt('auth'). Closes a leak surface that exposed the token via browser history, server access logs and the Referer header.sha256(token) instead of the clear token. The clear token never appears in wp_options.option_name either - DB-read attacks no longer yield a replayable token.wp_options on first load. Idempotent./wp-json/oembed/1.0/embed, the _embed=1 fanout on /wp/v2/posts, and wp-sitemap-users-N.xml. The lockout-side REST gate also denies oEmbed for locked IPs.subnet_of() and Detection\Classifier::compute_subnet() now produce a re-parseable canonical /64 from compressed IPv6 (2001:db8::1 → 2001:db8:0:0::/64). Subnet block rules entered against IPv6 attackers now match.0.0.0.0 placeholder. record_failed_attempt() and check_lockout() skip the literal placeholder returned by get_client_ip() when the configured proxy header is misconfigured. Prevents site-wide lockout on the shared placeholder.# BEGIN/END LoginArmor markers, with a legacy fallback) is stripped.LockoutPage::render_on_trigger now performs a 302 redirect to /[hide-slug]/?_la_locked=<timestamp>. The unique query string defeats every public page cache (LiteSpeed Cache, WP Rocket, Cloudflare full-page, hosting reverse-proxy). Verified live with Playwright Firefox 150 + httpx HTTP/2.LoginArmor::flush_response_and_exit() now mirrors WordPress core's _default_wp_die_handler exactly (no fastcgi_finish_request). Under LiteSpeed/LSAPI, calling fastcgi_finish_request() after a 4xx with a custom body left HTTP/2 streams without END_STREAM, hanging Firefox/Chromium. HTTP/2 lockout response now arrives complete in 1.3 s.output_buffering=4096 on most managed hosts) was capturing the body. LoginArmor::flush_response_and_exit() now discards every parent buffer before writing the response. Same helper is used by Hide Login's 404 renderer and Hardening's XML-RPC + access-denied responses, so all three paths inherit the fix.login_armor_lockout_triggered fires after the lockout marker is committed; LockoutPage subscribes and renders inline.?ver=X.Y.Z from script and stylesheet URLs at script_loader_src priority 9999.