Modernizing OpenWrt Security: Implementing 2FA and WebAuthn

现状

经过努力,已经把luci-plugin-2fa和对应的登录补丁合并进OpenWRT的luci代码库,可以直接从新版(大概是25.x之后)下载luci-plugin-2fa软件包使用。

欢迎前往我独立的 luci-plugin-2fa 代码库点个 Star,感谢支持!

起因

OpenWrt 自 2004 年诞生以来,一直是大量路由器系统的基石。即便其功能与性能不断进化,但在账号安全认证方面,LuCI(其 Web 界面)长期停留在传统的“用户名+密码”模式。在当今网络攻击手段日益多样的环境下,这种单一的认证方式显得有些力不从心。

在立项之初,我查阅了社区资料,发现官方一直缺乏原生的 2FA 组件。虽然在 Issue #8273 中可以看到社区曾有过零星的尝试,但大多由于架构限制或开发者断更,最终都停留在不可用的状态。最接近成功的一次是 PR #7069,它实现了 TOTP 算法的基础,但由于未能解决登录逻辑的耦合问题,原作者也已查无此人,项目随之搁浅。

在接手这个挑战时,我并没有预料到,真正的难点并不在 2FA 算法本身,而是在于 OpenWrt 沿用了十几年的登录架构。

修改架构:重新设计登录流程

在深入研究 PR #8281 时,我意识到 LuCI 之前的登录链过于线性且缺乏原子化。原始的逻辑可以概括为:

输入凭据 -> 验证 -> 立即生成 Session -> 登录完成

这种强耦合的逻辑被硬编码在核心分发器(Dispatcher)中,完全没有给第三方模块留出干预空间。若直接在这个链条里强行塞入 2FA 逻辑,会导致代码极其臃肿且难以维护。

在方案选择上,直接拦截(HOOK)核心分发器文件虽然实现路径较短,但这种做法缺乏优雅性,会带来巨大的维护风险,本质上是在原有的技术债务上继续堆叠。考虑到未来还需加入验证码(Captcha)或 WebAuthn 等认证方式,这种打补丁式的开发模式是完全不负责任的。

为了从根本上解决问题,我与 OpenWrt 核心开发者 @systemcrash 进行了多次深入沟通。我们在讨论中明确了插件系统的概念与设计。通过在登录过程中引入“多阶段验证钩子”机制,将登录流程重塑为:

输入凭据 -> 基础验证 -> 调用认证钩子(2FA/LDAP等) -> 全部通过后生成 Session

这种设计将 2FA 转化为一个可选的增强插件,消除了必须修改核心代码的束缚。相较于传统的硬编码方式,这种原子化的重构为后续支持 WebAuthn 等现代化安全协议打下了稳健的底层基础。

2FA 的实现细节

在解决了底层架构后,PR #8280 的实现就变得水到渠成了。对于 TOTP(基于时间的一次性密码)算法,我利用了现成的 uqr 库来生成配置所需的二维码,降低了系统的依赖负担。

在开发过程中,安全性与稳健性是考量的核心。相较于简单的 Demo,合入官方库的代码需要考虑多种边缘情况,例如:

  1. 时钟同步问题:路由器如果 NTP 同步失败,会导致 TOTP 验证失效,因此增加了显眼的同步提示。
  2. 紧急恢复方案:一旦用户丢失手机或误删密钥,需要有后台重置机制。
  3. UI 适配:确保在各种移动端浏览器上都能正常显示验证界面。

整个过程经历多次代码审查(Code Review),最终得到了官方维护者的认可并成功合入主干。

未来展望:拥抱 WebAuthn

目前的 2FA 主要是基于 TOTP 的验证码,虽然安全,但在用户体验上仍有提升空间。我目前正在推进 luci-plugin-webauthn 的开发工作。

相比 TOTP 验证码,WebAuthn 允许用户使用指纹、FaceID 或是 Yubikey 等硬件密钥进行身份认证。这不仅是安全性上的跃升,更能实现“无感登录”。虽然这部分的实现涉及更复杂的加密挑战与浏览器交互,但我相信它会成为 OpenWrt 安全体系中的重要一环。

从一个简单的 Issue 到最终合入官方主干,这段经历让我深刻体会到:在开源社区,实现一个功能往往只需几行代码,但若要构建一个通用的标准架构,则需要反复的推敲与对细节的极致追求。

Current Status

Through persistent effort, both luci-app-2fa and the corresponding login patches have been merged into the official OpenWrt LuCI repository. Users can install the luci-app-2fa package directly in new versions (expected from 25.x onwards).

Please visit my independent luci-plugin-2fa repository and give it a Star. Your support is greatly appreciated!

The Origin

Since its inception in 2004, OpenWrt has served as the foundation for countless router systems. While its features and performance have evolved significantly, the security authentication of its web interface, LuCI, has remained stagnant, relying on the traditional username and password model. In an era of increasingly sophisticated network threats, this single-factor authentication has become insufficient.

At the start of this project, I reviewed community resources and found that the official repository lacked a native 2FA component. Although Issue #8273 showed sporadic community attempts, most stalled due to architectural constraints or lack of maintenance. The most promising attempt was PR #7069, which implemented a basic TOTP algorithm. However, it failed to address the coupling of the login logic, and the original author eventually disappeared, leaving the project abandoned.

Taking on this challenge, I realized that the primary obstacle was not the TOTP algorithm itself, but rather the login architecture that OpenWrt had utilized for over a decade.

Restructuring the Architecture: Redesigning the Login Flow

While analyzing PR #8281, I discovered that the existing LuCI login chain was overly linear and lacked atomicity. The original logic followed a rigid sequence:

Input Credentials -> Verification -> Immediate Session Generation -> Login Complete

This tightly coupled logic was hardcoded within the core Dispatcher, leaving no room for third-party modules to intervene. Attempting to force 2FA logic into this existing chain would have resulted in bloated and unmaintainable code.

When considering solutions, simply hooking the core Dispatcher file offered a shorter path to implementation, yet such an approach lacked elegance and introduced significant maintenance risks. It would essentially amount to piling more complexity onto existing technical debt. Given the potential need to integrate other authentication methods such as Captcha or WebAuthn in the future, a “patchwork” development style was deemed irresponsible.

To resolve this fundamentally, I engaged in several deep discussions with core OpenWrt developer @systemcrash. These consultations led to the definition and design of a Plugin System. By introducing a multi-stage verification hook mechanism into the login process, we reshaped the flow as follows:

Input Credentials -> Base Verification -> Call Authentication Hooks (2FA/LDAP, etc.) -> Generate Session after total approval

This design transforms 2FA into an optional enhancement plugin, removing the requirement to modify core code for every security feature. Compared to the traditional hardcoded method, this atomic restructuring provides a stable foundation for supporting modern security protocols like WebAuthn.

2FA Implementation Details

Once the underlying architecture was resolved, the implementation of PR #8280 became straightforward. For the Time-based One-Time Password (TOTP) algorithm, I utilized the existing uqr library to generate the necessary configuration QR codes, thereby minimizing system dependencies.

During development, security and robustness remained the top priorities. Compared to a simple demonstration, code intended for the official repository must account for various edge cases, including:

  1. Clock Synchronization: If the router fails to sync via NTP, TOTP verification will fail. To address this, I added prominent synchronization warnings.
  2. Emergency Recovery: A backend reset mechanism was implemented in case a user loses their phone or deletes their secret key.
  3. UI Adaptation: Ensuring the verification interface renders correctly across various mobile browsers.

The entire process underwent multiple rounds of code review before receiving approval from the official maintainers and being merged into the main branch.

Future Outlook: Embracing WebAuthn

While current 2FA implementation focuses on TOTP codes, there is still room to improve the user experience. I am currently advancing the development of luci-plugin-webauthn.

Compared to TOTP codes, WebAuthn allows users to authenticate using fingerprints, FaceID, or hardware keys like Yubikey. This represents a leap in both security and convenience, enabling a passwordless login experience. Although this implementation involves more complex cryptographic challenges and browser interactions, I am confident it will become a vital part of the OpenWrt security ecosystem.

Moving from a simple Issue to a final merge into the official main branch has taught me a valuable lesson: in the open-source community, implementing a feature may only require a few lines of code, but building a universal, standard architecture requires deep reflection and a relentless pursuit of detail.


Modernizing OpenWrt Security: Implementing 2FA and WebAuthn
https://tski.uk/blog/openwrt-advance-security/
作者
Tokisaki Galaxy
发布于
2026年5月27日
许可协议