跳至内容
WordPress.org

China 简体中文

  • 主题
  • 插件
  • 新闻
    • 文档
    • 论坛
  • 关于
  • 获取 WordPress
获取 WordPress
WordPress.org

Plugin Directory

DollarMates U2 Secured Authenticator

  • 提交插件
  • 我的收藏
  • 登录
  • 提交插件
  • 我的收藏
  • 登录

DollarMates U2 Secured Authenticator

作者:dollarmates
下载
  • 详情
  • 评价
  • 安装
  • 开发进展
支持

描述

U2 Secured Authenticator adds push-based two-factor authentication to WordPress login. After a user’s
password is verified, WordPress holds the session open (it does not complete it) and challenges for a
second factor:

  • Tap-to-approve push — a number-match approval sent to the user’s phone via the U2 Secured app.
  • TOTP fallback — a standard six-digit authenticator-app code, for when a push can’t reach the
    phone. Verified on your own server: the RFC 6238 check runs in PHP against the secret this site
    already holds (encrypted at rest), with the same ±1 window tolerance for clock drift, and no request
    leaves the site to do it. Requires the sodium PHP extension and an encryption key (see
    Installation); the plugin says so plainly on the profile screen when it isn’t available, rather than
    silently dropping the option. Wrong codes are rate-limited per user (five inside fifteen minutes)
    so a six-digit code cannot simply be ground through.
  • Recovery codes — ten single-use codes issued when a user links their device, verified entirely
    locally against WordPress’s own database.

    Both fallbacks are what make the failure mode of an unreachable U2 API survivable: the push path is
    dead, but a linked user can still sign in with either, because neither makes an outbound call. They
    share one field on the fallback screen, which accepts whichever the user has to hand.

  • Role-based enforcement with a grace period — require two-factor for chosen roles (e.g.
    Administrator) without locking out every matching user the instant it’s switched on. Each user gets a
    configurable number of days to link before they’re actually blocked.
  • Step-up re-auth — a small set of sensitive admin capabilities (e.g. installing plugins) can
    require a fresh tap before they’re usable, even mid-session.
  • Optional signed webhook — U2 Secured can POST the outcome of an approval straight to this site
    the moment the user taps, so the login screen can answer from local state instead of asking again.
    It is an optimisation and nothing more: every delivery must carry a valid signature to be believed,
    and login works identically on a site that never receives one, because the browser asks U2 Secured
    for the outcome itself anyway. Sites that aren’t reachable from the public internet should simply
    skip it.
  • XML-RPC / Application Passwords awareness — XML-RPC authenticates with the raw password and never
    reaches the wp_login hook this plugin relies on, so it’s explicitly closed off. Application
    passwords are a legitimate WordPress feature, so instead of being silently broken they’re surfaced to
    the administrator as an admin notice.

Every enrolment is opt-in until an administrator turns on role-based enforcement. Every error path —
an unreachable U2 API, a missing encryption key, an unrecognised device, a removed or rotated-out API
key
— is designed to fail closed: the safe outcome is “ask again” or “refuse,” never “let the
request through.” A user who requires a second factor on a site that can no longer perform one is
refused and told to ask an administrator; they are not quietly let in. See Verification status in
README.md for exactly what is and isn’t proven by the automated tests, and please read it before
enabling enforcement on a production site.

The escape hatch

If a user loses their phone and their recovery codes, the only way back in is an administrator
running, over SSH:

wp u2auth disable <user>

<user> accepts a WordPress user ID, login, or email address. This clears the plugin's local

two-factor state for that user (it does not touch anything on the U2 side, so it works even when the
U2 API is unreachable) and immediately admits them again — they can re-link from their profile once
back in. wp u2auth status <user> reports whether a user is currently linked and how many recovery
codes they have left, without changing anything.

External services

This plugin cannot work on its own: approving a login means asking a phone, and that request
travels through the U2 Secured Authenticator service at https://auth.u2secured.com. Installing
the plugin does not by itself send anything — nothing leaves your site until an administrator
enters an API key and a user links a phone.

When the site contacts the service

  • When a user links their phone: to mint a one-time pairing code, then once every few seconds
    until the code is redeemed or expires, and once more to read the resulting link.
  • When a linked user opens their own profile screen, to read whether their phone is still
    linked and able to receive approvals.
  • When a linked user signs in, to ask their phone to approve it, and then once every two
    seconds until they answer or the request expires.
  • When a linked administrator performs a sensitive action (installing a plugin, editing a
    user), for the same approval round trip.
  • When a user unlinks their phone, to remove the link on the U2 side as well.
  • When an administrator presses “Test connection” on the settings screen.

What is sent

  • An identifier for the user, in the form <random site id>|<numeric WordPress user ID>. The
    site id is a random string generated once and stored in your database. Your users’ email
    addresses, usernames and passwords are never sent
    , and neither is your site’s URL.
  • Your site’s name (from Settings → General), so the person looking at their phone can see
    which site is asking.
  • For a sensitive admin action, the name of that action — for example “Install a plugin”.
  • While a phone is being linked, the one-time pairing code the service itself just issued; while
    an approval is outstanding, the id of that approval. Neither is derived from anything about
    the user.
  • Your site’s API key, to authenticate the request.

What is never sent

  • Recovery codes and TOTP codes, and the TOTP secret itself. Both fallback factors are
    checked inside PHP on your own server — recovery codes against hashes in your database, TOTP
    against the secret your site holds (RFC 6238, ±1 window) — so no request is made to check
    either, and the shared secret never leaves the site after enrolment. Earlier releases did send
    the TOTP secret and the submitted code to the service to be checked; 0.3.0 stopped.
  • Passwords, usernames, email addresses, and your site’s URL.

Service terms: https://auth.u2secured.com/terms
Privacy policy: https://auth.u2secured.com/privacy

安装

  1. Upload the plugin to /wp-content/plugins/dollarmates-u2-secured-authenticator (or install the zip through
    Plugins → Add New), then activate it.

  2. Create an app in the U2 Secured developer portal and copy its server API key
    (rka_...). This key is what lets the plugin request push approvals, mint pairing codes and read
    enrolments. It is not used to check TOTP or recovery codes — both are verified on your own server.

    Keep it in place once users have enrolled. Removing or rotating it out does not switch
    two-factor off; it makes the push factor impossible, and a user who requires a second factor is then
    refused at login rather than let through. Use wp u2auth disable <user> (below) if you need to
    release someone.

  3. Add the API key to wp-config.php. A wp-config.php constant is preferred over the plugin’s own
    settings screen because it isn’t copied into every database backup:

    define( ‘U2AUTH_API_KEY’, ‘rka_…’ );

    (The settings screen at Settings → U2 Secured still accepts it as a fallback for sites that can’t
    edit wp-config.php — but the constant always wins, and the field is disabled on the settings screen
    once it’s set.)

  4. Add a second constant, U2AUTH_ENCRYPTION_KEY. This one gates a security control: it is the key
    used to encrypt the site-held TOTP secret at rest, so that a database dump alone doesn’t hand over
    working two-factor secrets alongside the accounts they protect. Without it, the TOTP fallback is
    unavailable (the plugin says so on the profile screen and in an admin notice; push and recovery
    codes still work) rather than storing the secret unencrypted.

    define( ‘U2AUTH_ENCRYPTION_KEY’, ‘<32 random bytes, base64>’ );

    Generate a value with:

    php -r ‘echo base64_encode(random_bytes(32)), PHP_EOL;’

    Requires the sodium PHP extension, which ships enabled by default on PHP 7.2+.

  5. Visit Settings → U2 Secured. The Getting started panel there repeats these steps and
    reports which of them this site has actually completed, and Test connection checks the API key
    and base URL against U2 Secured with a single read-only request — so a wrong key is something you
    find out by pressing a button, not by being locked out at your next login. The same screen is where
    you optionally:

    • pick which roles are required to use two-factor (leave every role unticked to keep linking opt-in),
    • set the grace period, in days, a newly-required user gets before they’re actually blocked.
  6. Optional: set up the webhook. In the developer portal, point your application’s webhook at the
    URL shown in step 4 of the Getting started panel. Take it from there rather than constructing
    it: the URL depends on your site address and your permalink settings, the panel shows the single
    form that is correct for your site as it is configured, and a stale URL in the portal fails
    silently. On most sites it reads:

    https://example.com/wp-json/u2auth/v1/webhook

    and on a site using plain permalinks, https://example.com/?rest_route=/u2auth/v1/webhook. If you
    change your permalink settings later, come back and copy the new URL across.

    Then give this site the signing secret the portal shows for that webhook, so it can tell a real
    delivery from a forged one:

    define( ‘U2AUTH_WEBHOOK_SECRET’, ‘…’ );

    (Again, the settings screen accepts it as a fallback. An unsigned, wrongly signed, or stale
    delivery is rejected, and with no secret configured at all every delivery is rejected — “not
    configured” is never read as “accept anything”.)

    Skip this step entirely if the site isn’t reachable from the public internet — a local install,
    an intranet site, anything behind NAT or a VPN. Nothing breaks: the login screen asks U2 Secured
    for the approval outcome itself, and always did. All the webhook saves is an outbound call or two.

  7. Each user links their own device from their own profile screen (Users → Profile, or Your
    Profile
    in the admin toolbar) — an administrator cannot link a device on another user’s behalf,
    since linking inherently needs that user’s own phone. Linking also issues ten single-use recovery
    codes, shown once and never shown again, so tell people to save them somewhere they can reach
    without their phone.

常见问题

What happens if a user loses their phone?

They fall back to a recovery code (issued, ten at a time, when they first linked, and shown again any
time they choose to regenerate them from their profile) or a TOTP code from a backup authenticator app,
if one was set up. If they’ve lost the phone and exhausted their recovery codes, an administrator
runs wp u2auth disable <user> over SSH — see “The escape hatch” above. This is a local, offline
operation: it works even if the U2 API itself is unreachable.

Does turning on role-based enforcement lock everyone out immediately?

No. A user in a newly-enforced role gets the configured grace period (default seven days) to link
before they’re blocked — they’re nagged on their profile screen, not refused at login, until that
window closes.

What happens if the U2 API is unreachable?

The plugin fails closed, and there is no setting that changes that — opting out is not offered.

In practice that is less dramatic than it sounds. An already-linked user cannot use the push challenge
while U2 is unreachable, but can still sign in with a recovery code or a TOTP code: both are verified
against this site’s own data with no outbound call at all. The login is still gated, just via a
different factor. If the phone is gone and the codes are exhausted, wp u2auth disable <user> over
SSH is the escape hatch, and it makes no network call either.

What the plugin will not do is let a session through with no second factor because a network call
failed. See “Fail-closed means a misconfiguration blocks logins” under Verification status in
README.md for what that means for your own rollout.

What happens if the API key is removed, or rotated out?

Users who require a second factor are refused, with a message telling them to ask an administrator to
check the key. They are not let in.

This is worth stating plainly because the alternative is the more tempting behaviour and it is a
two-factor bypass: wp_login fires after WordPress has already set the auth cookie, so a plugin that
merely declines to challenge when it is unconfigured has thereby completed the login. Up to and
including 0.2.2 this plugin did exactly that, and deleting the API key silently switched two-factor off
for every user who had it. Fixed in 0.3.0.

A site with the plugin installed and nobody enrolled is unaffected: it behaves exactly as WordPress
does, which is why the check asks “does this user need a second factor” before it asks “can this site
send one”.

What stops someone guessing a TOTP code?

Five wrong codes for one user inside fifteen minutes, and the TOTP factor refuses that user until the
window passes. Recovery codes are checked before the limit applies, so a user who fumbled their
authenticator app still has their codes — the limit is a brake, never a lockout, and it clears itself.

Each guess also costs a full password sign-in, because the challenge is single-use: a failed code
invalidates the attempt and the attacker has to authenticate the password again to get another.

Do I need the webhook?

No. It’s an optimisation, never a requirement. When a user taps Approve, U2 Secured can POST that
outcome to this site immediately; the login screen then answers from local state instead of asking U2
Secured again. Without it the login screen simply asks — which is what it does anyway while it waits.
Every login flow, fallback and failure mode is identical either way.

Set it up only if this site is reachable from the public internet. If it isn’t, deliveries would never
arrive and nothing would tell you so, which is worse than not configuring it. The URL to paste into
the developer portal is printed on Settings → U2 Secured, under Getting started — take it from
there rather than typing it out, since it follows your site address and your permalink structure, and
that screen already resolves which of the two forms your site actually uses.

What happens if someone forges a webhook delivery?

It’s rejected. Every delivery carries an HMAC signature over the exact bytes sent, computed with the
shared secret from U2AUTH_WEBHOOK_SECRET (or the settings screen), and is verified before a single
field of the payload is read. A wrong signature, a signature computed over different bytes, a stale
timestamp, or a malformed header are all refused and change nothing. If no secret is configured at
all, every delivery is refused — “not configured” is never treated as “accept anything”. A rejected
webhook can’t strand a login either: the browser’s own poll resolves the approval regardless.

Does this affect XML-RPC or Application Passwords logins?

XML-RPC authenticates with the raw password and never reaches the hook this plugin challenges on, so
the plugin closes it off outright rather than leaving a second, unguarded front door. Application
Passwords are a legitimate WordPress feature with their own use cases, so instead of being blocked
they’re surfaced as an admin notice — decide for your site whether to disable them separately.

Can an administrator link or unlink a device for another user?

No. Linking needs that user’s own phone, so there is no “link on behalf of” flow. The only admin-side
action is the wp u2auth disable / wp u2auth status escape hatch described above.

评价

此插件暂无评价。

贡献者及开发者

「DollarMates U2 Secured Authenticator」是开源软件。 以下人员对此插件做出了贡献。

贡献者
  • dollarmates

帮助将「DollarMates U2 Secured Authenticator」翻译成简体中文。

对开发感兴趣吗?

您可以浏览代码,查看SVN仓库,或通过RSS订阅开发日志。

更新日志

0.3.1

  • The TOTP attempt limit could be stretched by sending guesses in parallel. The five-per-15-minutes
    counter was advanced by reading it, adding one, and writing the result back. Two submissions that
    overlapped both read the same number and both wrote the same number, so one of the two guesses cost
    nothing — making the limit a function of how many requests were sent at once rather than how many
    guesses were made. The counter is now incremented atomically: through the object cache’s own
    increment where a persistent cache is available, and otherwise by a single self-referential SQL
    UPDATE that the database serialises. Reported by the plugin review team.

0.3.0

  • Security: a second factor could be skipped entirely on a site whose API key had been removed or
    rotated out.
    The login interception treated “this user requires a second factor” and “this site can
    perform one” as the same condition, and answered both by returning — but wp_login fires after
    WordPress has already set the auth cookie, so returning there completed the login. Any already-linked
    user therefore signed in with a password alone once the key was gone, which is the opposite of what
    this readme promised. Entitlement is now decided first and on its own: a user who needs a second
    factor and cannot be given one is refused, with a message naming the fix. A site with nobody enrolled
    still signs users in exactly as WordPress does.
  • TOTP codes are now verified on your own server, and the TOTP secret is no longer transmitted.
    Verification used to POST the shared secret and the submitted code to the U2 Secured API on every
    fallback login — while this readme said, in as many words, that TOTP codes are verified on your own
    server and never transmitted. The RFC 6238 check (same ±1 drift window, same answer) now runs in PHP
    against the secret this site already holds, so nothing goes on the wire, and a U2 outage no longer
    takes the TOTP factor down with push.
  • Wrong TOTP codes are rate-limited locally: five per user inside fifteen minutes. The remote endpoint
    applied a brute-force lockout shared across its callers, and moving the check in-house would
    otherwise have dropped that protection. Recovery codes are checked before the limit, so it can
    never become a lockout, and a throttled user is told they are throttled rather than told their code
    was wrong.
  • The fallback screen now says that an authenticator-app code is accepted there too. It always was —
    the one field takes a recovery code or a TOTP code — but every string around it said only “Recovery
    code”, so anyone with a backup authenticator app had no way to know.
  • README.md is now included in the plugin package. readme.txt refers readers to it by name for the
    verification-status detail and the fail-closed rollout warning, and it was being stripped out of the
    distributed zip, so both references resolved to nothing.
  • The “External services” disclosure now lists every call the plugin makes, including the enrolment
    read on the profile screen, the pairing-code poll and the unlink, and states explicitly what is never
    sent.

0.2.2

  • Fix: a refused second factor now answers HTTP 403 instead of 500. Every rejection in the login challenge —
    a mistyped or already-used recovery code, a lapsed sign-in attempt, and every login attempt by a user in an
    enforced role who has not enrolled yet — called wp_die() with no arguments, and wp_die() defaults to

    1. The page shown was always correct; only the status line said “Internal Server Error” for what is an
      ordinary, expected refusal. It matters because managed hosts, firewalls and CDNs alarm and rate-limit on
      5xx rates without reading the page, so a user fumbling their recovery codes could trip a false outage alert
      or be throttled before reaching the login screen again. The one path that genuinely cannot complete — a
      login fired from somewhere that cannot render the challenge screen — still answers 500, now explicitly.

0.2.1

  • Fix: the API key and webhook signing secret are stored exactly as entered. They were previously passed
    through sanitize_text_field(), which strips percent-encoded octets and tag-like sequences and collapses
    whitespace — so a credential containing any of those was silently stored as a different string and every
    later API call or webhook signature check failed with nothing on screen to explain it. Neither value is
    ever rendered back into the settings form, so nothing was gained by sanitising them.

0.2.0

  • Security: the API base URL is compiled into the plugin and is no longer an admin setting. The API key
    is sent to whatever host that URL names, so an editable field let anyone who reached wp-admin redirect
    the key to a server they control. U2AUTH_BASE_URL still overrides it on local and staging installs,
    and is ignored on production.
  • Signing in with a recovery code is now its own screen, reached from a “Use recovery code” link, rather
    than a code field sitting under “approve on your phone”.
  • Step-up approval offers a recovery code. Previously an outage, a revoked enrolment or a rotated API key
    sealed every gated capability behind a request that could never succeed, with no route back short of
    shell access to the server.
  • Failures say what actually went wrong. A rejected API key and an unenrolled account were both reported
    as “we could not reach U2 Secured”, which sent people looking for an outage that was not happening.
  • Fixed: updated CSS and JavaScript never reached browsers, because every asset URL carried a version
    string that never changed.
  • The step-up screen’s text is now translatable; it was previously hardcoded English.
  • Licence changed to GPLv2 or later.

0.1.0

  • Initial release: tap-to-approve push challenge on login, TOTP and recovery-code fallback, role-based
    enforcement with a grace period, step-up re-authentication for sensitive admin actions, XML-RPC /
    Application Passwords handling, the optional signed approval.resolved webhook receiver, a guided
    setup panel with a connection test on the settings screen, and the wp u2auth disable /
    wp u2auth status WP-CLI escape hatch.

额外信息

  • 版本 0.3.1
  • 最后更新:2 天前
  • 活跃安装数量 不到10
  • WordPress 版本 6.0 或更高版本
  • 已测试的最高版本为 7.1.3
  • PHP 版本 7.4 或更高版本
  • 语言
    English (US)
  • 标签
    2FAloginsecuritytwo factor
  • 高级视图

评级

尚未提交反馈。

您的评价

查看全部评论

贡献者

  • dollarmates

支持

有话要说吗?是否需要帮助?

查看支持论坛

  • 关于
  • 新闻
  • 主机
  • 隐私
  • 陈列窗
  • 主题
  • 插件
  • 区块样板
  • 学习
  • 支持
  • 开发者
  • WordPress.tv ↗︎
  • 参与
  • 活动
  • 捐赠 ↗
  • 周边商品 ↗
  • WordPress.com ↗
  • Matt ↗
  • bbPress ↗
  • BuddyPress ↗
WordPress.org

China 简体中文

The WordPress® trademark is the intellectual property of the WordPress Foundation.

  • 关注我们的 X(原 Twitter)账号
  • 访问我们的 Bluesky 账号
  • 关注我们的 Mastodon 账号
  • 访问我们的 Threads 账号
  • 访问我们的 Facebook 公共主页
  • 关注我们的 Instagram 账号
  • 关注我们的 LinkedIn 主页
  • 访问我们的 TikTok 账号
  • 访问我们的 YouTube 频道
  • 访问我们的 Tumblr 账号
代码如诗