Freeradius 3.2.10 基于密码的企业级安全认证实现
如何实现企业级的网络安全认证
总体思路
从前面 《Freeradius 3.2.10 环境搭建以及 PAP 和 CHAP 两种认证方式的测试》 介绍我们知道,如果基于密码认证的方式,无论认证方式选择 PAP 或者是 CHAP,实际上都很弱鸡。既然 CHAP 和 PAP 在公网上传输不安全,最直接的思路就是:先建一条 TLS 加密隧道,把认证报文丢进隧道里传。外层 TLS 隧道的作用是提供安全的隐形管道,内层协议的作用仅仅是 “在这条安全管道里,客户端如何向服务器证明我是我”。这就是目前基于密码的安全网络环境的标准做法。
常见的几种方案
这里的名称确实五花八门,容易被绕晕,但只要抓住了 “外层建隧道,内层传密码” 这个核心逻辑,所有概念瞬间就会变得非常清晰。在 RADIUS 认证中,EAP(扩展认证协议)其实是一种两层嵌套结构:
- 外层协议(TLS / PEAP / TTLS):负责建立一条加密隧道(安全快递盒),防止黑客在网络中窃听。
- 内层协议(PAP / CHAP / MS-CHAPv2 / GTC):装在加密隧道内部的具体凭据(信封里的账号密码或挑战码)。
1 | ┌─────────────────────────────────────────────────────────────┐ |
对四个词汇的拆解:
- TLS(Transport Layer Security):传输层安全协议(就是 HTTPS 用的加密协议)。在 RADIUS 里,直接叫 EAP-TLS 时代表双向数字证书认证(不用密码,靠证书)。这个 TLS 既可做外层,也可做独立方案。
- PEAP(Protected EAP):受保护的 EAP。由微软/思科主导的外层加密隧道协议。规定内层必须封装另一个 EAP 协议。它是一个纯外层隧道。
- TTLS(Tunneled TLS):隧道化 TLS。由 Funk/FSH 主导的外层加密隧道协议。极其自由,内层可以直接传原始属性或普通协议(如 PAP)。它也是一个纯外层隧道。
- EAP(Extensible Authentication Protocol):扩展认证协议。它不是具体算法,而是一个通用框架,上面的 PEAP、TTLS、TLS、MS-CHAPv2 全都是它的具体实现。
明白了 “外层” 和 “内层” 的区别,我们来看看企业里最常出现的几种组合:
- EAP-TTLS + PAP:自建数据库的最佳选择。
- 外层(TTLS):开辟一条 TLS 加密通道。
- 内层(PAP):在加密管道里直接发送明文密码。
- 这么配置是最佳搭档,因为外层已经绝对安全,内层用 PAP 让服务器解密出明文后,可以拿着去和数据库里的 BCrypt / Argon2 强哈希做比对。既防抓包,又防数据库泄漏。
- EAP-PEAP + EAP-MSCHAPv2:微软/AD 域控的标准默认。
- 外层(PEAP):开辟一条加密通道。
- 内层(EAP-MSCHAPv2):在通道里跑微软特有的 MS-CHAPv2 挑战-响应协议。
- Windows 电脑、iOS、Android 原生对这个组合支持最好。服务器不需要存明文密码,只需要存微软 AD 域控默认的 NT-Hash 即可。
- EAP-PEAP + EAP-GTC:动态口令 / 2FA 专用。
- 外层(PEAP):加密通道。
- 内层(EAP-GTC):通用令牌卡协议(Generic Token Card)。
- 用来传输一次性动态验证码(OTP)、Google Authenticator 验证码或硬件令牌。
- EAP-TLS:无密码,纯证书。
- 不分内外层,或者说内外层都是 TLS。
- 不用输入任何账号密码。员工电脑里有一张私有证书,服务器也有证书,两者双向验证证书成功即通网。零信任和金融机构最爱,安全性最高,但维护成本也最高。
1 | 你要用什么方式验证身份? |
EAP-TTLS + PAP
前面我们已经搭建了最基础的 freeradius 测试环境,参考 《Freeradius 3.2.10 环境搭建以及 PAP 和 CHAP 两种认证方式的测试》 。我们将在原基础上继续实现 EAP-TTLS + PAP 方案。
建库建表
freeradius 对不同的数据库都提供了支持,官方建表语句放在 mods-config/sql/main 目录下。找到对应的 mysql/schema.sql,将建表语句在对应的已经建好的数据库中执行(比如我们建的库的名称是 radius3)。数据库中初始化一条测试账户:
1 | # 生成一条 bcrypt测试密码 |
1 | -- 插入测试用户 owlias01,密码 123456 的 BCrypt 哈希。使用了 $2a$ 格式的 BCrypt 哈希,FreeRADIUS 的 pap 模块原生支持解析 |
Freeradius 配置修改
第一,修改 /etc/raddb/mods-available/sql
1 | sql { |
开启 freeradius 的 sql 模块。在宿主机对应的 volume 挂载点执行:
1 | cd xxx/mods-enabled |
第二,修改 EAP 模块文件 /etc/raddb/mods-available/eap
1 | eap { |
第三,修改 /etc/raddb/sites-available/default(外层 Virtual Server),负责处理网络入口的 EAP 握手。确保 authorize 节点开启了 eap 模块:
1 | authorize { |
第四,修改 /etc/raddb/sites-available/inner-tunnel(内层 Virtual Server - 最关键)。这是最核心的一步:当外层 TTLS 隧道建立成功后,FreeRADIUS 会将解密出来的明文 PAP 请求扔进这个 inner-tunnel 进行数据库比对。
1 | server inner-tunnel { |
第五,修改 /etc/raddb/mods-available/pap
1 | pap { |
最后,重启 freeradius 服务器:
1 | docker-compose up -d |
测试验证
我们在 radius-client 容器中进行测试。
1 | $ docker exec -it radius-client bash |
在宿主机使用 wireshark 实时抓包。抓包文件请参考 freeradius-ttls-pap-success-pack.pcap。请使用curl -C - -O xxx 命令进行下载。
1 | $ docker exec radius-server tcpdump -i eth0 -U -w - "udp port 1812 or port 1813" | /Applications/Wireshark.app/Contents/MacOS/Wireshark -k -i - |
在宿主机实时观察 freeradius -X 日志:
1 | $ docker logs -f radius-server |
运行测试:
1 | # 这里 -a 172.18.1.3 是指向的 radius 服务器地址(eapol_test 不支持使用域名) |

认证过程分析
完整认证流程图
1 | [客户端 (eapol_test)] [FreeRADIUS 服务器] |
阶段一
外层 TLS 握手与加密隧道建立(Outer Tunnel):此阶段的目标是在不安全的网络介质上,建立一条受 TLS 保护的安全加密管道。
1 | [客户端 (eapol_test)] [FreeRADIUS 服务器] |
Step 1-2:身份声明与协议切
- 客户端提交外层身份 User-Name = “owlias01”(若开启匿名,外层通常为 anonymous)。
- 服务器收到后,回应 EAP-TTLS Start,通知客户端准备开启 TLS 握手。
Step 3-4:TLS 握手与证书下发
- Client Hello:客户端向服务器发送支持的 TLS 版本(如 TLS 1.2/1.3)和加密套件列表(Cipher Suites),并附带客户端随机数 Client Random。
- Server Hello:服务器挑选加密套件(如 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384),并附带服务器随机数 Server Random。
- Certificate(下发服务器证书):
- 下发内容:服务器将自身的实体证书(Server Certificate)以及中间 CA 证书链发送给客户端。
- 证书细节(结合抓包数据):Subject、Issuer…
- 客户端如何校验服务器证书?👈🏻
- 客户端拿到服务器证书后,必须在本地完成以下 4 项校验:
- 签名链有效性(Chain of Trust):客户端使用本地预存的 ca.pem(根证书)的公钥,去解密并校验服务器证书上的 CA 签名。若能解开且哈希匹配,证明证书确实由信任的 CA 颁发。
- 有效期检查(Validity):检查当前时间(如 2026-07-22)是否处于证书的 notBefore 与 notAfter 之间。
- 域名/身份匹配(Subject Matching):检查证书的 CN 或 SAN 是否匹配客户端配置预期的服务器名称。
- 证书吊销状态(CRL/OCSP):检查证书是否在吊销列表
- 客户端拿到服务器证书后,必须在本地完成以下 4 项校验:
Step 5-6:密钥交换与隧道激活
- 客户端生成 Pre-Master Secret,通过 ECDHE/RSA 算法与服务器交换。
- 双方利用 Client Random + Server Random + Pre-Master Secret 共同算出对称密钥 Master Secret。
- 双方发送 Change Cipher Spec 和 Finished 报文,TLS 加密管道正式建立。
阶段二
隧道内 PAP 凭据传输与数据库校验(Inner Tunnel):此阶段的目标是在安全的 TLS 隧道保护下,安全地传输用户明文密码并完成身份鉴权。
1 | [客户端 (eapol_test)] [FreeRADIUS 服务器] |
Step 7:内层 PAP 请求发送。
- 客户端将真正的敏感凭据打包为 AVP(Attribute-Value Pairs)送入 TLS 隧道:
- User-Name = “owlias01”
- User-Password = “123456” (即便在 PAP 中它是明文,但在外层 TLS 隧道的包裹下是绝对安全的)
Step 8:FreeRADIUS 内部校验过程。
- 触发 inner-tunnel 虚拟服务器:FreeRADIUS 收到解密后的内层请求,将请求交由 sites-enabled/inner-tunnel 处理。
- 执行 sql 模块:
- 执行查询:SELECT attribute, value FROM radcheck WHERE username = ‘owlias01’
- 查出数据库中的密码哈希:Crypt-Password = “$2b$10$wQ7tX5M…”
- 执行 pap 模块:
- pap 模块拿到客户端传来的明文 User-Password(123456)和数据库中的 Crypt-Password(BCrypt 哈希)。
- 调用底层的 C 库 crypt() 函数,对明文应用相同盐值的 BCrypt 计算,比对摘要值。
- 比对成功,返回 [pap] = ok。
Step 9:成功响应。
- inner-tunnel 返回内层 Access-Accept
- 外层 FreeRADIUS 收到内层成功通知,将最终的 EAP-Success (Code 3) 封装在 RADIUS Access-Accept (Code 2) 报文中,回复给客户端/NAS 设备。