跳到主内容

用于 VPN 和 Wi-Fi 的 RADIUS 多因素身份验证:结合 Casdoor RADIUS Server 的 TOTP 2FA

· 阅读时间:一分钟
Yang Luo
Casdoor Maintainer

要在 VPN 前通过 RADIUS 实现多因素身份验证,VPN 网关使用 PAP 将用户名和密码发送到 RADIUS 服务器,服务器验证密码后回复 Access-Challenge,客户端显示提示,用户从身份验证器应用中输入 2FA 代码作为第二个请求的一部分。Casdoor 提供了一个 RADIUS 服务器,正好为设置了 TOTP 的用户执行此操作,因此能够显示 Access-Challenge 提示的网关(FortiGate SSL VPN 是供应商文档中说明支持这一点的其中一个)可以获得密码加上 2FA 代码,而无需任何额外软件。Wi-Fi 与 WPA2/WPA3-Enterprise 不同:802.1X 运行在 EAP 之上,EAP 没有位置供输入代码,因此 Casdoor 有一个开关可以为这些客户端跳过代码步骤。

如果您想了解 RADIUS 本身的背景知识及其在网络设备方面与 LDAP 的比较,请先阅读 RADIUS vs LDAP。本文重点介绍 MFA 部分:传输的数据内容、哪些客户端可以承载第二因素,以及如何在 Casdoor 中启用它。

哪些客户端可以通过 Casdoor 进行 RADIUS MFA​

下表列出了各供应商文档中记录的内容。“Challenge support”表示客户端向用户显示 Access-Challenge 提示并将答案发回。如果我们查阅的供应商页面未提及,表格会如实说明,而不是猜测。

客户端与 Casdoor 配合使用的 RADIUS 认证方法Access-Challenge 支持情况备注
FortiGate SSL VPNPAP(将方法设置为 PAP,或保留 Default,这会首先尝试 PAP)是,根据 Fortinet 文档Fortinet 表示 SSL VPN 会将挑战转发给客户端并等待回答
FortiGate IPsec VPN(包括 FortiClient)PAP默认不转发Fortinet 的解决方案要求 RADIUS 服务器使用 MS-CHAP,而 Casdoor 不支持此协议;请使用 SSL VPN 或跳过 MFA
Cisco ASA (AnyConnect / Secure Client)PAP,这是 ASA 对所有连接类型的默认设置ASA RADIUS 配置指南中未说明不要在隧道组上启用 password-management:这会将 ASA 切换为 MS-CHAPv2
OpenVPN Access ServerPAP(它也提供 CHAP 和 MS-CHAPv2)RADIUS 设置页面中未说明计费(Accounting)是一个单独的开关,默认端口为 1813
pfSense(RADIUS 认证服务器,由其 OpenVPN 使用)PAP(也支持 MD5-CHAP, MS-CHAPv1, MS-CHAPv2)Netgate 文档中未说明Netgate 的 OTP 示例将代码放在密码字段内,而 Casdoor 不接受这种方式
WireGuard无不适用对等方仅通过公钥进行身份验证,因此没有可供 RADIUS 检查的登录过程
Wi-Fi, WPA2/WPA3-Enterprise (802.1X)EAP (PEAP, EAP-TTLS 等)无输入代码提示Casdoor 未实现 EAP;参见 Wi-Fi 部分

如果单元格显示“not stated”,请在全面部署前使用实际的 VPN 客户端进行测试,并确认提示出现且代码能够通过。

为什么只有 PAP 能承载 Casdoor 检查的密码​

RADIUS 有几种发送密码的方式,它们决定了服务器能够验证什么。

使用 PAP 时,客户端将密码放入 User-Password 属性中,并通过共享密钥和请求认证器的 MD5 哈希进行隐藏(RFC 2865,第 5.2 节)。服务器使用相同的密钥还原该值,获取明文密码,并可以将其与存储的哈希或 LDAP 绑定进行检查。Casdoor 读取 User-Password 并执行与其登录页面相同的密码检查。

使用 CHAP 时,客户端从不发送密码。它发送密码和一个随机挑战值的哈希。RFC 2865 明确指出,CHAP 需要在服务器端拥有用户的明文密码以重新计算该哈希。MS-CHAPv2 具有相同的结构,但使用 NT 哈希。将密码存储为单向哈希的身份提供商(Casdoor 内置的组织使用 bcrypt)无法验证其中任何一种。Casdoor RADIUS 服务器仅读取 User-Password,因此 CHAP 或 MS-CHAPv2 请求到达时没有密码,会被拒绝。

由于 PAP 的隐藏仅使用带有共享密钥的 MD5,请使用长随机密钥,在网关和 Casdoor 之间将 RADIUS 保留在私有网络或 VPN 上,并在客户端启用 Message-Authenticator 属性。当请求携带 Message-Authenticator 时,Casdoor 会对其进行验证并在此情况下签署其回复,这是针对 Blast-RADIUS (CVE-2024-3596) 的缓解措施。详细信息请参阅 RADIUS 服务器文档。

Access-Challenge 与将代码附加到密码​

通过 RADIUS 传递 2FA 代码有两种常见方式。

  1. Access-Challenge。服务器检查密码,然后回复 Access-Challenge、一个 State 属性和一个 Reply-Message。客户端显示消息,用户输入代码,客户端发送一个新的 Access-Request,其中包含 User-Password 中的代码和相同的 State。RFC 2865 第 4.4 节还说明了在不支持挑战的客户端上会发生什么:它必须将 Access-Challenge 视为 Access-Reject。
  2. 将代码附加到密码。用户在单个密码字段中输入 password123456,服务器分离出最后六位数字。这适用于任何客户端,这就是为什么为旧网关构建的产品提供此功能的原因。

Casdoor 仅实现第一种方式。以下是其 RADIUS 服务器 (radius/server.go) 中的流程:

  • 第一个 Access-Request 必须携带正确的密码。启用了 MFA 的用户会收到 Access-Challenge、一个随机的 State 以及 Reply-Message please enter OTP。
  • State 有效时间为 120 秒且只能使用一次。它与第一个请求的组织和用户名相关联。
  • 第二个 Access-Request 必须携带该 State 以及来自用户身份验证器应用的六位 TOTP 代码,位于 User-Password 中。Casdoor 根据用户的 TOTP 密钥检查代码,并回答 Access-Accept 或 Access-Reject。
  • 错误的代码计入用户应用的登录失败限制(默认为 5 次尝试和 15 分钟冻结),这与错误的密码分开计算。

由此产生两个后果。只能执行“密码加代码在一个字段中”的客户端将会失败,因为 Casdoor 将整个字符串作为密码进行检查。并且只有 TOTP 可以通过 RADIUS 工作:短信和电子邮件代码需要 Casdoor 在密码步骤后发送消息,而 RADIUS 服务器不会这样做。唯一 MFA 方法是短信或电子邮件的用户会在收到挑战后被拒绝,因此请让 RADIUS 用户设置身份验证器应用。

Wi-Fi: 802.1X 和 WPA-Enterprise​

在使用 WPA2-Enterprise 或 WPA3-Enterprise 的 Wi-Fi 上,接入点本身不收集密码。它中继设备( supplicant )和 RADIUS 服务器之间的 EAP 会话,RADIUS 在 EAP-Message 属性中承载 EAP 数据包。在这种设置中,Access-Challenge 已经在使用中:EAP 交换的每次往返都是 Access-Request 和 Access-Challenge 对(RFC 3579)。RFC 3579 还规定携带 EAP-Message 的消息不得包含 Reply-Message,因此没有用于“请输入 OTP”的字段,也没有在手机或笔记本电脑上输入代码的对话框。

对于 Casdoor 的两个实际要点:

  • Casdoor 的 RADIUS 服务器未实现 EAP。接入点无法直接与其通信以进行 WPA-Enterprise。你需要在前面有一个 EAP 服务器来终止 TLS 隧道并转发普通的 PAP 请求。FreeRADIUS 可以通过将 EAP-TTLS 和 PAP 作为内部方法来实现这一点,将内部请求代理到另一个 RADIUS 服务器,并且设备必须设置为 TTLS 且内部使用 PAP。许多设备默认的 PEAP 配合 MS-CHAPv2 无法针对 Casdoor 工作,原因见 PAP 部分所述。
  • 对于这些用户,请在组织上启用 Skip MFA for RADIUS。Casdoor 随后将在仅完成密码检查后接受拥有 MFA 的用户。Web 登录页面上的 MFA 不受影响。

端口、共享密钥和记账​

RFC 2865 将 UDP 端口 1812 分配给 RADIUS 身份验证,RFC 2866 将 1813 分配给记账。Casdoor 监听一个 UDP 端口 radiusServerPort,并在那里处理 Access-Request 和 Accounting-Request。因此,请将网关的记账指向与身份验证相同的端口(默认为 1812),而不是 1813,否则记账数据包将无处可去。如果 Casdoor 在容器中运行,请以 UDP 发布端口,例如 -p 1812:1812/udp。

共享密钥是所有客户端的一个值 radiusSecret。每个与 Casdoor 通信的网关都使用它。

对于记账,Casdoor 在其数据库(表 radius_accounting)中记录 Start、Interim-Update 和 Stop 消息,包括会话 ID、会话时间、NAS 地址、Framed IP 以及字节和数据包计数器。它仅对启用了 RADIUS 的组织执行此操作。

配置 Casdoor​

1. 设置 RADIUS 选项。 在 conf/app.conf 中,或使用相同名称的环境变量:

radiusServerPort = 1812
radiusDefaultOrganization = "my-company"
radiusSecret = "a-long-random-string-shared-with-the-gateway"

radiusDefaultOrganization 是当请求没有 Class 属性时 Casdoor 使用的组织。如果你的网关无法在其请求中添加 Class 属性,此设置决定了哪些组织的用户通过 RADIUS 登录。所有键均列在配置参考中。

**2. 为组织启用 RADIUS。**在组织编辑页面上,开启 Enable RADIUS。该选项默认关闭,且仅全局管理员可以更改。当该选项关闭时,Casdoor 会拒绝该组织的所有 Access-Request 请求并忽略其计费信息。

**3. 确定 RADIUS 的 MFA 策略。**对于支持 Access-Challenge 的 VPN 网关,请保持 Skip MFA for RADIUS 处于关闭状态。对于无法响应挑战的 RADIUS 客户端所在的组织(例如 WPA-Enterprise Wi-Fi),请将其开启。

**4. 让用户配置 TOTP。**用户需从个人资料页面设置验证器应用,具体步骤请参阅多因素认证。若要使其成为强制要求,请在组织的 MFA 项目下添加带有 Required 规则的 TOTP 项。请注意顺序:如果用户尚未设置必需的 MFA,或必须先修改密码,则在 Casdoor 登录页面完成这些操作之前,RADIUS 认证将被拒绝。

**5. 从命令行进行测试。**FreeRADIUS 的 radclient 发送 PAP 请求并打印回复:

echo 'User-Name = "alice", User-Password = "her-password"' \
| radclient -x casdoor.example.com:1812 auth a-long-random-string-shared-with-the-gateway

对于使用 TOTP 的用户,您应该看到包含 State 和 Reply-Message 的 Access-Challenge。请在 120 秒内使用该 State 将代码回传:

echo 'User-Name = "alice", User-Password = "123456", State = 0x...' \
| radclient -x casdoor.example.com:1812 auth a-long-random-string-shared-with-the-gateway

将第一次回复中的 State 值粘贴到 0x... 的位置。收到 Access-Accept 表示设置正确,接下来配置网关即可。

如果您还希望 Casdoor 使用外部 RADIUS 服务器作为其自身 Web 登录的第二因素,这是相反的方向,由 RADIUS MFA 提供商涵盖。

参考资料​