內容簡介
A little more secure 外掛旨在防止機器人透過暴力破解攻擊 wp-login.php。透過引入解鎖參數和非同步的登入表單,這個外掛提高了自動化攻擊的成本,並提供了一個更安全的登入方式。
【主要功能】
• 防止暴力破解攻擊
• 自動生成解鎖參數
• 支援自訂解鎖規則
• 提供登入表單的 nonce 檢查
• 可設定重定向延遲時間
外掛標籤
開發者團隊
原文外掛簡介
Stop bots from brute force hacking your wp-login.php
A request to wp-login.php without an unlock parameter answers with a 404 and a
holding page. JavaScript counts down a few seconds, then redirects to the same
URL with the parameter appended. Only that request renders a usable login form,
and only it carries the nonce that a login POST has to contain — a POST without
a valid nonce is rejected.
This raises the cost of naive automation. It is not a lockout mechanism: whoever
requests the unlock URL first can read the nonce and post with it, which is why
the plugin is called a little more secure.
There is nothing to configure. Activating the plugin is enough.
Customising
Three filters, for a theme or a small plugin of your own.
a_little_more_secure_is_unlocked decides whether a request counts as unlocked.
By default that is the presence of the parameter; override it to implement your
own rule, for example a one-time token or an office IP allowlist:
add_filter( 'a_little_more_secure_is_unlocked', function ( $is_unlocked ) {
return $is_unlocked || my_own_check();
} );
a_little_more_secure_get_param_name changes the name of the unlock parameter,
a-little-more-secure by default.
a_little_more_secure_redirect_wait_seconds changes the delay before the
redirect, 3 seconds by default.
A theme with its own login form that posts to wp-login.php has to render the
nonce itself, otherwise the POST is rejected — call
a_little_more_secure_nonce_field() inside the form. Forms built with
wp_login_form() get it automatically.
Rotating the unlock parameter
The default parameter name is public knowledge, so a bot written for this plugin
can hardcode it. If you want a name that changes over time, put the token in the
name itself: the parameter name filter runs both when the redirect URL is built
and when the request is checked, so both sides agree without storing anything.
function my_alms_token( int $bucketsAgo = 0 ): string {
$ttl = 15 * MINUTE_IN_SECONDS;
$bucket = (int) floor( time() / $ttl ) - $bucketsAgo;
return 'alms_' . substr( hash_hmac( 'sha256', 'alms|' . $bucket, wp_salt( 'nonce' ) ), 0, 20 );
}
add_filter( 'a_little_more_secure_get_param_name', function () {
return my_alms_token();
} );
add_filter( 'a_little_more_secure_is_unlocked', function ( $is_unlocked ) {
return $is_unlocked || isset( $_GET[ my_alms_token( 1 ) ] );
} );
Accepting the previous bucket as well keeps a request that crosses a bucket
boundary from being rejected, so the effective validity is 15 to 30 minutes.
Keep the token alphanumeric — PHP rewrites dots and spaces in parameter names.
Be aware of what this does and does not do. It stops bots that hardcode the
parameter name. It does not stop anything that fetches the page and reads the
name out of it — the value has to be handed to the browser before anyone is
logged in, so a scraper can always obtain it too.
Three things to expect: bookmarked unlock URLs stop working once the token
expires, though an expired token lands on the holding page and is redirected
with a fresh one, so it costs one extra request. Keep the lifetime well above
the redirect delay, otherwise the token can expire during the countdown. And be
careful with page caching — a short-lived token in cached HTML means logins that
are rejected until the cache is refreshed.
