从报文到实验:用FreeRADIUS读懂RADIUS认证协议
发布时间:2026/9/29 15:44:11来源:尧图网络
简介RADIUS协议是远程认证拨号用户服务的简称广泛用于网络接入场景下的认证、授权与计费。面向网络工程师、运维人员及高校网络课程学习者既可作为内部培训教材也适合需要理解RADIUS认证流程的初学者自学。压缩包共1个文件为doc格式文档大小4.69MB文档目录完整从RADIUS协议简介、报文结构、常用属性类型列表到NAS设备RADIUS部分配置举例再到RADIUS系统下用户认证过程层层递进并附有培训目标与前言便于培训时快速定位教学重点。报文结构中逐域拆解Code、Identifier、Length、Authenticator和Attributes并列出常用属性类型认证过程部分更以16个报文完整串联EAPOL-Start、EAP-Request/Identity、Access-Request、Access-Challenge、Access-Accept、Accounting-Request/Response、EAPOL-Logoff、EAP-Failure等关键交互直观展示用户上线认证、计费与下线全流程帮助理解共享密钥加MD5加密校验、挑战应答等机制。文档可作为教案直接用于授课也适合在配置Radius服务器或排查认证失败时对照查阅目前已有160人学习。1. RADIUS协议还在服役这篇教案要解决的是「看不懂报文」的痛点RADIUS协议从RFC 2865一路走到今天校园网准入、企业Wi-Fi、运营商宽带认证里它仍然是最常见的那个中间人接入设备NAS把用户名密码丢给它由它决定放行还是拒绝。可很多人学RADIUS是从概念图开始的画一堆认证请求、认证响应的箭头真拿到一份抓包文件就蒙了——Code是什么、Authenticator怎么算、User-Password为什么不是明文。这篇教案想让学员从报文层面真正看懂RADIUS同时把FreeRADIUS搭起来亲手跑一遍认证、授权和计费再自己排查共享密钥、NAT、计费丢包这类真实环境里的问题。适合网络运维、安全测试和刚开始接触AAA体系的人照着复现。2. 拆开RADIUS协议报文从Code、AVP到认证授权计费三元组2.1 认证时RADIUS站在哪里从NAS到RADIUS Server的一跳RADIUS是个典型的中间判断协议。用户终端先对接入设备说话接入设备交换机、无线控制器、BRAS统一叫NAS把凭证整理成Access-Request发给RADIUS ServerServer查完用户库后回Access-Accept或Access-RejectNAS再根据响应放行或拒绝。整个过程中用户终端并不直接和RADIUS Server通信它甚至感知不到RADIUS的存在。这个一跳的架构是理解后面所有问题的前提。很多人误以为RADIUS是用户和服务器之间的长连接其实它只是NAS与Server之间的UDP报文交换一个请求一个响应认证完就结束关系不维持会话。这也决定了它天然无状态Server挂了NAS侧只会看到请求超时用户连不上Wi-Fi而不是收到一个明确的错误码。教案里我会让学生先把这句话记下来RADIUS不管用户后边的流量只负责进门时盘一遍和出门时记一笔。从一个典型场景看更清楚。员工笔记本连公司Wi-FiWPA2-Enterprise走PEAP或EAP-TLS无线控制器作为NAS把用户名和EAP报文封装进RADIUS Access-Request转发给后端的FreeRADIUS或Windows NPS。认证通过后NAS下发VLAN或ACL策略。所以RADIUS报文里经常看到的是NAS-IP-Address、Called-Station-Id、Calling-Station-Id这类设备侧属性而不是终端侧的网络层信息。2.2 报文骨架Code、Identifier、Length、Authenticator与AVPRADIUS报文是典型的二进制TLV结构固定20字节头部后面跟着一串Attribute。头部五个字段里Code决定报文类型Identifier是8位的请求序号Length是整包长度Authenticator是16字节的校验与加密种子最后是可变长的属性区。理解这个骨架比背RFC更重要因为后面所有调试都靠它。下面这个Python脚本可以从UDP载荷里把RADIUS报文拆开我在教案里经常让学生先跑通它再去做任何抓包分析import struct ATTR_NAMES { 1: User-Name, 2: User-Password, 3: CHAP-Password, 4: NAS-IP-Address, 5: NAS-Port, 6: Service-Type, 8: Framed-IP-Address, 26: Vendor-Specific, 30: Called-Station-Id, 31: Calling-Station-Id, 40: Acct-Status-Type, 44: Acct-Session-Id, } CODE_NAMES { 1: Access-Request, 2: Access-Accept, 3: Access-Reject, 4: Accounting-Request, 5: Accounting-Response, 11: Access-Challenge, } def parse_radius(pkt: bytes): # 头部固定20字节Code(1) Identifier(1) Length(2) Authenticator(16) code, ident, length struct.unpack(!BBH, pkt[:4]) authenticator pkt[4:20] print(fCode{code} ({CODE_NAMES.get(code, unknown)})) print(fIdentifier{ident} Length{length}) print(fAuthenticator{authenticator.hex()}) pos 20 while pos length: t, l pkt[pos], pkt[pos 1] value pkt[pos 2:pos l] name ATTR_NAMES.get(t, fAttr-{t}) print(f {name}: len{l}, value{value.hex()}) pos l这段代码里有个细节值得在课堂上强调struct.unpack(!BBH, pkt[:4])用的是网络字节序大端因为RADIUS和几乎所有TCP/IP协议一样多字节字段按big-endian传输。Length字段包含了20字节头部本身所以如果Length40说明有20字节属性。循环解析AVP时每个AVP的Length包含Type和Length自己那两字节pos l直接跳到下一个属性靠的就是这个自描述特性。AVP才是RADIUS真正干活的地方。User-Name是明文用户名User-Password不能明文传它用MD5(共享密钥 Request Authenticator)按16字节一组异或加密NAS-IP-Address记录发起方Vendor-Specific是给厂商自定义属性留的通道很多计费、QoS策略都藏在这里。教案里我会让学生先记住6个属性1、2、4、6、26、40其余用到再查。2.3 认证、授权、计费三个流程状态机与典型时序RADIUS的AAA三件事对应三组报文但它们的走向完全不同。认证是Access-Request到Access-Accept/Reject/Challenge的问答授权不是一个独立请求而是认证响应里携带的Service-Type、Framed-IP-Address、Session-Timeout这些属性NAS收到同意就按属性执行计费是单独的Accounting-Request/Response分为Start和Stop两个端点。流程触发方向核心报文关键AVP认证NAS - ServerAccess-Request / Access-Accept / Access-RejectUser-Name, User-Password, NAS-IP-Address授权随认证响应由Accept属性承载Service-Type, Framed-IP-Address, Session-Timeout计费NAS - ServerAccounting-Request / Accounting-ResponseAcct-Status-Type, Acct-Session-Id, Acct-Session-Time认证流程可以看作一个简单的状态机NAS发送后等待Accept或Reject如果收到Access-ChallengeCode11说明Server要求二次认证比如PEAP里的内层EAP交换这时NAS需要发起新一轮请求并带上State属性。很多第一次做EAP-PEAP对接的人会在Challenge这一步翻车因为把这个当成超时重发结果Identifier错位Server端日志全是duplicate request。计费流程的坑在UDP上。Accounting-Request发出去后NAS会按自己的定时器重发直到收到Response或放弃。所以Server端要做去重同一个Acct-Session-Id的Start报文连发两次第二次要识别成重复请求而不是新建计费会话。这正是Identifier和Authenticator配合解决的另一个问题后面第5章展开。把这三条流程串起来就是一份完整教案的主线先讲认证如何放行再讲授权如何限权最后讲计费如何留痕。三个流程对应三组抓包学生做完就有全局观不会只盯着那一条Access-Request。3. 用FreeRADIUS搭最小实验环境从安装到radtest跑通认证3.1 安装并初始化Debian系一条龙动手教案的最佳载体是FreeRADIUS因为它带完整的调试工具和默认测试用户装完就能跑。我一般建议在虚拟机里做用Debian系的apt安装保证依赖干净、路径一致减少环境差异带来的排障干扰。sudo apt update sudo apt install -y freeradius freeradius-utils sudo systemctl enable --now freeradius systemctl status freeradius --no-pager这三行命令里freeradius是服务端主程序freeradius-utils里带radtest、radclient、radmin这些调试工具缺一不可。装完以后systemctl status应该显示active状态如果显示failed多半是端口被占或默认配置里有模块启动失败先用sudo freeradius -X前台跑一次看报错。这个-X前台调试模式在后面排障里会反复用到它会把每个请求的处理流程打到终端上比翻journal日志直观得多。装完先别急着改配置直接用默认值验证环境是通的。Debian系FreeRADIUS默认配置在/etc/freeradius/3.0/下clients.conf里内置了localhost测试客户端共享密钥是testing123授权文件里内置了testing用户密码是password。用radtest打一发就知道服务端基本功能正常radtest testing password 127.0.0.1 1812 testing123如果看到rad_recv: Access-Accept说明服务端已经能完整处理一次认证。这一步如果失败先确认1812端口在监听ss -ulnp | grep 1812能查再确认没有别的进程抢占了端口。默认配置跑不通的时候不要继续往下做基础环境不干净后面所有实验结论都会失真。3.2 配置NAS客户端与共享密钥clients.conf和users文件默认配置只能证明安装没问题要让学生理解“NAS是客户端Server是服务端”这个关系就要自己加一个模拟NAS的条目。编辑/etc/freeradius/3.0/clients.conf在文件末尾加client lab_nas { ipaddr 192.168.56.0/24 secret lab_secret_2024 shortname lab-nas nas_type virtual }这是个典型的网段级client配置。ipaddr可以写单个IP也可以写网段实验环境里最好写网段免得之后换虚拟机IP又要改配置。secret是NAS和Server之间的共享密钥两边必须一字不差这里建议用带年份的随机串方便后面做密钥不一致的故障注入实验。shortname只是日志里的显示名nas_type填virtual是告诉FreeRADIUS这不是真实硬件型号避免它按厂商规则做特殊处理。接下来加用户。老教程让你写/etc/freeradius/users那是FreeRADIUS 2.x的路径3.x里对应的是/etc/freeradius/3.0/mods-config/files/authorize由mods-enabled/files模块加载。在文件末尾添加labuser Cleartext-Password : lab123456 Service-Type Framed-User, Framed-IP-Address 192.168.56.101, Session-Timeout 3600第一行是用户名和密码:表示直接赋值Cleartext-Password是告诉服务端按明文密码比对而不是走别的hash方式。下面三行就是授权部分Service-Type说明这是拨号/框架用户Framed-IP-Address是认证通过后下发给用户的IPSession-Timeout是3600秒后强制会话下线。这三行正好对应2.3节的授权概念学生改这里就能直观看到授权属性如何影响最终会话。改完重启服务让配置生效sudo systemctl restart freeradius重启这一步经常有人漏掉。FreeRADIUS在启动时读一次配置文件之后用SIGHUP能热加载部分文件但clients.conf的变更还是重启最稳妥。如果改完测试还是旧行为先别怀疑代码多半是服务没重读配置。3.3 radtest与抓包验证Access-Request到Access-Accept配置完以后用radtest验证这次用自己的用户和密钥radtest labuser lab123456 127.0.0.1 1812 lab_secret_2024radtest的参数依次是用户名、密码、服务器地址、端口和共享密钥。实际工作中NAS设备也是干同样的事只不过它把用户名和密码封装成EAP之类更复杂的报文。如果返回Access-Accept你的FreeRADIUS已经能处理一个来自虚拟NAS的认证请求如果返回Access-Reject用sudo freeradius -X看日志会看到密码校验失败的明确记录。要让学员看见协议光看radtest输出不够得上抓包sudo tcpdump -i lo -nn -X -s 0 udp port 1812 or udp port 1813在另一个终端再跑一次radtesttcpdump窗口里就能看到Access-Request和Access-Accept两个包。注意这里抓的是lo接口因为radtest和FreeRADIUS在同一台机器上走回环地址。重点看两个包Request里的Authenticator是一串随机hexResponse里的Authenticator是服务端算出来的这串值就是第5章讲校验失败时要用到的关键证据。抓完包可以顺手验证一下客户端口。radtest默认从本机随机端口发出但真实NAS会固定源端口有些设备锁定1812。如果服务端防火墙只放行了目的端口1812而radtest从随机端口发出响应就会被拦。这个细节放到第5章是真实环境里最常见的误配置之一。4. 把原理落成教案三张表、一个抓包演示和五道报文阅读题4.1 教案结构怎么排先故事后协议栈再报文教案的核心不是讲完PPT而是让学员在60分钟内自己抓到并读懂一个RADIUS包。我常用的排布是5分钟场景引入、10分钟协议栈定位、20分钟报文解剖、20分钟实验验证、5分钟答疑。这个结构把理论时间压缩到一半剩下全部动手。时间段环节产出物0-5min为什么Wi-Fi要单独认证学生说出“接入点不信任终端”这个直觉5-15minRADIUS在AAA里的位置画出NAS、RADIUS Server、用户库的关系图15-35min报文解剖学生能说出Code、Identifier、Authenticator的作用35-55minradtest抓包实验每组抓到一对Request/Accept并做标注55-60min两个坑的快速演示密钥不一致和端口不对的表现这里说的三张表分别是报文类型表、关键AVP表、AAA流程表分别对应2.2和2.3的内容。我上课时会把三张表打印成一张A4纸发给学生报文类型表用来查CodeAVP表用来对属性流程表用来理清认证、授权、计费分别在哪一步发生。有了三张表学生不需要在课堂上记任何东西所有精力放在读包上。为什么这么排因为RADIUS本身不复杂复杂的是它和NAS、认证协议、计费系统的关系。先让学生知道“它是个中间判断者”再看报文里怎么表达这件事最后动手验证理解曲线比“先讲RFC再讲排障”平滑得多。这个排序我调过好几次最初版本先讲EAP再讲RADIUS学员被PEAP的隧道搞晕后来改成先抓包后讲EAP反而更容易接受。4.2 课堂演示脚本让Access-Request的每个字段对上演进过程演示环节要有一个能反复跑的脚本我把它做成一个bash脚本放在每台实验机上学生双击就能复现一份完整的认证抓包#!/usr/bin/env bash # 用法: ./demo_auth.sh cd /tmp sudo tcpdump -i lo -nn -X -s 0 udp port 1812 -w radius_demo.pcap sleep 1 radtest labuser lab123456 127.0.0.1 1812 lab_secret_2024 sleep 2 sudo kill %1 echo 抓包文件: /tmp/radius_demo.pcap这个脚本的思路是后台起tcpdump写pcap文件前台跑一次radtest两秒后停掉抓包。注意tcpdump的过滤条件只抓1812端口这样pcap里不会混进计费流量学生打开Wireshark只需要看两个包。-w写文件的格式比终端-X输出更适合教学因为在Wireshark里能看到RADIUS协议自动解码后的字段名不需要肉眼看hex。讲课时我会让学生盯着Wireshark的四个字段Request里的Code1、Identifier0、Authenticator那串随机数以及Accept里Code2、Identifier0。Identifier相同是因为这是同一个对话的请求和响应为的是让NAS能把响应和请求对上。这个“Identifier匹配”的概念学生在TCP里已经见过序列号迁移过来很快。脚本里有个细节tcpdump路径固定写死-i lo如果机器上radtest走的是eth0而不是回环就抓不到包。所以脚本开头可以加一行判断让学生先跑ip addr确认127.0.0.1路由到哪个接口再填-i参数。这个“先确认流量路径再抓包”的习惯比脚本本身更值得教。4.3 考核题设计不背概念直接读报文教案要能验收但我不建议出概念填空。最好的考核是给一段真实的hex报文让学生手工解析。下面这段是从Access-Request里截出来的前几个字段01 00 00 34 4f 6b 3a 12 8a 2b 91 c3 46 e9 8a 3d 7a 0a c2 1e 01 08 6c 61 62 75 73 65 72 ...五道题可以这样出第一题Code是多少代表什么报文第二题Identifier是多少如果Accept里Identifier不一致客户端会怎么处理第三题Length0x34换算成十进制是多少个字节验证一下后面十六进制串的长度是否吻合第四题User-Name属性的Type是多少、Length是多少、值是什么第五题把Accept的Identifier改掉让学生分析客户端是放行还是丢弃。能在三分钟内答对前四题的学生说明真的看懂了报文骨架而不是背熟了流程图。第五题其实是找茬题考的是Identifier在UDP无连接环境下承担匹配责任也是后续理解重传和去重的基础。这五道题加上前面的实验动手基本能筛出“理解协议”和“只会敲命令”的差别。实操里我发现能独立解析报文的学生后面排查NAS对接问题时上手极快因为他们知道报错信息里每个字段的上下文。如果学生机器没装Wireshark用tshark -r radius_demo.pcap -V也能看到同样的字段考核时允许用但要求必须解释字段含义而不是只抄结果。5. RADIUS协议避坑共享密钥、NAT、重传与计费丢包5.1 Access-Reject但用户没问题共享密钥不一致的典型症状现象radtest返回Access-Reject但用户数据库里密码明明对服务端日志也没有“密码错误”的明确记录。原因共享密钥不一致时服务端和客户端各自计算的校验值对不上。Access-Request里User-Password用客户端侧密钥加密服务端用自己的密钥解密出的是乱码比对自然失败。更典型的是Access-Accept的Response Authenticator客户端验不过有些NAS直接显示认证拒绝有些显示超时具体看设备厂商的实现。解决第一步在服务端前台跑sudo freeradius -X看日志里有没有密码校验失败相关信息。第二步分别查看NAS设备和clients.conf里的secret注意不能只看字符一样后面不能有多余空格配置文件里的引号和缩进也会导致读取出错。第三步用radtest换一个已知正确的密钥重试隔离问题在Server还是NAS侧。5.2 认证超时UDP、NAT与防火墙的三角关系现象同一套配置在内网测试正常部署到跨网段后认证请求经常超时用户投诉Wi-Fi连上但打不开登录页。原因RADIUS走UDPNAT设备通常只维护一段时间内的地址映射。认证请求通过NAT出去后响应回来时映射如果已老化就会被丢弃。另一个坑是防火墙只放行了目的端口1812却忽视了RADIUS响应是从1812端口返回给NAS的导致回包被拦。还有老设备默认发1645/1646端口而新服务端监听1812/1813两边端口不匹配也会表现为超时。解决优先让NAS与RADIUS Server二层可达不走NAT如果必须跨网段在防火墙上放行“源端口1812/1813、目的端口1812/1813”的双向策略。同时把NAS上的重传间隔调大比如从默认3秒改成5秒重传次数从2次改成4次给UDP丢包留出余量。修改后不要只在客户端测试要从RADIUS Server端抓包确认请求到达和响应发出的时间戳定位丢包到底发生在前半段还是后半段。5.3 计费丢包Acct-Request重传与实时计费失效现象用户能正常上网认证日志也没问题但下线后账单里时长缺失或流量对不上计费系统里看到大量超时状态的会话。原因计费是UDP报文走1813端口丢了就是丢了不像TCP有重传。虽然NAS会按定时器重发Accounting-Request但如果服务器处理不过来或网络抖动频繁连续丢几次计费会话就断了。服务器端已经标记过Start的会话收不到Stop就成了永远挂起的状态。解决服务端开启报文去重和会话恢复。FreeRADIUS里检查计费表是否有唯一索引按Acct-Session-Id去重NAS侧调大计费重传次数把Interim-Update间隔从默认的300秒缩短到120秒缩短丢包窗口。更重要的排查手段是统计1813端口的请求和响应数量差当连续一段时间请求数明显大于响应数时就要检查服务器处理能力而不是继续调参数。5.4 Authenticator校验失败报文被改还是算法写错现象服务端日志出现Invalid Access-Request或Authenticator failed客户端却坚持说自己发的是正常请求。原因Access-Request的Authenticator是客户端生成的16字节随机数服务端用它参与User-Password的解密Access-Accept的Authenticator是服务端用MD5(CodeIdentifierLengthRequestAuthenticatorAttributes共享密钥)算出来的。任何一个环节算错校验就失败。常见原因有三个共享密钥不一致、中间安全设备修改了报文内容、调试时手工构造报文把长度或填充算错。解决抓包拿到Request和Response的原始hex用Python或Wireshark重新计算一遍。把共享密钥、Request Authenticator、属性区按顺序拼好做MD5和收到的值逐字节对比。这一步能分出三类错误密钥错、属性区被改、算法实现错。教案里我让学生亲手算一次算完就不会再被吊诡现象吓住。5.5 端口与源地址限制ACL不生效的另一半原因现象认证已经通过用户也拿到了IP但下发的ACL或VLAN策略不生效流量走向不对。原因授权属性下发成功不等于NAS会执行。有些NAS要求RADIUS响应里的源地址必须匹配clients.conf里登记的NAS-IP-Address否则丢弃或忽略属性。另一种常见情况是只写了Framed-IP-Address没写Framed-IP-Netmask设备不知道掩码就拒绝下发。还有很多老设备只支持部分AVPVendor-Specific里的策略被静默丢弃。解决先在抓包里确认Access-Accept里确实带了期望的授权属性再确认NAS型号支持的属性列表。用radtest配合手动指定属性组合测试排除“属性值合法但设备不支持”的情况。最后在NAS上看会话的active策略如果属性到了但不生效多半是设备侧映射配置问题和RADIUS Server无关。6. 教案进阶用抓包回放与故障注入把验证做扎实6.1 用tcpreplay回放认证流程做回归实验环境的回归测试我会用tcpreplay把抓到的pcap原样打回给FreeRADIUSsudo tcpreplay --intf1eth0 --topspeed --loop3 radius_demo.pcap回放需要先确认pcap里的目的MAC指向本机网卡否则报文到了链路层就被丢弃。--topspeed按抓包时间戳尽快发--loop3连续回放三遍用来观察服务端对重复请求的处理正好测试5.3节说的Identifier去重。因为RADIUS的Authenticator在重放时不变User-Password是用同一个Request Authenticator加密的服务端会正常解密并响应所以它更适合验证服务端在重复请求压力下是否稳定而不是模拟攻击。6.2 故障注入改错Authenticator让学生排障我会把排障变成实验课的一道题用scapy把请求里的Authenticator翻转一位再发出去让学生从服务端日志里看到校验失败然后自己查原因。from scapy.all import * pkt rdpcap(/tmp/radius_demo.pcap)[0] raw bytes(pkt[UDP].payload) # 翻转第5个字节即Authenticator的第一个字节 broken raw[:4] bytes([raw[4] ^ 0xff]) raw[5:] send(IP(dst127.0.0.1)/UDP(sport1812, dport1812)/broken)这段脚本把原始请求的Authenticator头部第一个字节翻转再重新封装成UDP包发给服务端。代码注释里写清楚了偏移RADIUS请求的前4字节是Code、Identifier、Length第5到20字节是Authenticator所以raw[4]就是Authenticator的起点。学员看到服务端日志里出现校验失败但用户密码完全正确就会意识到“能到服务端的包不等于没被篡改”。这个练习比任何PPT都更能建立对Authenticator的信任感。回放和注入这套组合拳做下来学员对RADIUS的报文、密钥、UDP特性都有了实际体感。我带实验课时最深的教训是不要替学生把环境调好保留一个故意配错密钥的现场让学员自己找到问题比顺畅跑通的实验课记忆深刻得多。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网