SIP鉴权过程
2024年11月30日 13:00-22:00
2024年12月1日-12月3日
在SIP终端注册或呼叫时,为了安全起见,SIP Server通常需要对用户(主叫)的身份进行认证。
注册流程
上面的SIP注册流程图,了解SIP的应该都很熟悉吧。这里笔者以X-Lite注册1015到FreeSWITCH为例讲述注册的鉴权过程。讲述时主要侧重鉴权,其它字段就不一一解释了。
X-Lite发起第一次REGISTER
首先X-Lite向FreeSWITCH发送第一个REGISTER消息。该消息不带任何鉴权信息,详细信令如下:
REGISTER sip:www.freeswitch.com SIP/2.0
Via: SIP/2.0/UDP 172.20.10.6:50024;branch=z9hG4bK-524287-1---e4fb8a53caa2f313;rportMax-Forwards: 70
Contact: <sip:1015@172.20.10.6:50024;rinstance=8466b9f513858577>
To: "1015"<sip:1015@www.freeswitch.com>
From: "1015"<sip:1015@www.freeswitch.com>;tag=61a25f79Call-ID: 89320ZWY3ZWVmNGVhODBiMzUzYWQwM2U3NWE4YTVmMWJlY2YCSeq: 1 REGISTER
Expires: 3600
Allow: SUBSCRIBE, NOTIFY, INVITE, ACK, CANCEL, BYE, REFER, INFO, OPTIONS, MESSAGEUser-Agent: X-Lite release 5.1.0 stamp89320Content-Length: 0
FreeSWITCH响应第一次REGISTER
FreeSWITCH收到后,发现X-Lite未带相关鉴权信息,则会回复401以告知需要鉴权,详细信令如下:
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 172.20.10.6:50024;branch=z9hG4bK-524287-1---e4fb8a53caa2f313;rport=50024
From: "1015"<sip:1015@www.freeswitch.com>;tag=61a25f79
To: "1015" <sip:1015@www.freeswitch.com>;tag=pjeF9m9c63Nym
Call-ID: 89320ZWY3ZWVmNGVhODBiMzUzYWQwM2U3NWE4YTVmMWJlY2Y
CSeq: 1 REGISTER
User-Agent: FreeSWITCH-mod_sofia/1.9.0+git~20180119T195505Z~3f8585f636~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, PRACK, NOTIFY, PUBLISH, SUBSCRIBE
Supported: precondition, 100rel, timer, path, replaces
WWW-Authenticate: Digest realm="www.freeswitch.com", nonce="3135ef65-3466-4f70-8035-ec70ff10ae75", algorithm=MD5, qop="auth"
Content-Length: 0
注意这里的FreeSWITCH带了一个WWW-Authenticate头。里面告知了如下几个重要的信息:
algorithm
:加密方式采用MD5
nonce
:FreeSWITCH生成的随机值
realm
:域名
X-Lite发起第二次REGISTER
于是X-Lite重新向FreeSWITCH发送了一个REGISTER信息,但是这次带了鉴权需要的信息,详细信令如下:
REGISTER sip:www.freeswitch.com SIP/2.0
Via: SIP/2.0/UDP 172.20.10.6:50024;branch=z9hG4bK-524287-1---72d5473edb7a7742;rport
Max-Forwards: 70
Contact: <sip:1015@172.20.10.6:50024;rinstance=8466b9f513858577>
To: "1015"<sip:1015@www.freeswitch.com>
From: "1015"<sip:1015@www.freeswitch.com>;tag=61a25f79
Call-ID: 89320ZWY3ZWVmNGVhODBiMzUzYWQwM2U3NWE4YTVmMWJlY2YC
Seq: 2 REGISTER
Expires: 3600
Allow: SUBSCRIBE, NOTIFY, INVITE, ACK, CANCEL, BYE, REFER, INFO, OPTIONS, MESSAGE
User-Agent: X-Lite release 5.1.0 stamp 89320Authorization:Digest username="1015",realm="www.freeswitch.com"nonce="3135ef65-3466-4f70-8035-ec70ff10ae75",uri="sip:www.freeswitch.com",response="d702aa1a84ecc11dc83f4a7c4e56c39a"cnonce="be28d6ed344661886ad93c8504358936",nc=00000001,qop=auth,algorithm=MD5
Content-Length: 0
注意这里比第一次REGIETER消息多了Authorization头。其中:
algorithm
:加密方式采用MD5(同401)
nonce
:FreeSWITCH生成的随机值(同401)
realm
:域名(同401)
username
:用户名,这里等同于注册号码
cnonce
: X-Lite生成的随机值
url
:SIP注册时的url
nc
:nonce-count,请求的计数
response
:加密后的密码
FreeSWITCH响应第二次REGIETER
FreeSWITCH通过相同的方式计算加密后的密码,并与X-Lite发送的(response
字段)比对,一致则鉴权通过并返回200。详细信令如下:
SIP/2.0 200 OK
Via: SIP/2.0/UDP 172.20.10.6:50024;branch=z9hG4bK-524287-1---72d5473edb7a7742;rport=50024
From: "1015"<sip:1015@www.freeswitch.com>;tag=61a25f79
To: "1015" <sip:1015@www.freeswitch.com>;tag=QU77agtg3ccHg
Call-ID: 89320ZWY3ZWVmNGVhODBiMzUzYWQwM2U3NWE4YTVmMWJlY2YCSeq: 2 REGISTER
Contact: <sip:1015@172.20.10.6:50024;rinstance=8466b9f513858577>;expires=3600
Date: Tue, 30 Jan 2018 14:48:35 GMT
User-Agent: FreeSWITCH-mod_sofia/1.9.0+git~20180119T195505Z~3f8585f636~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, PRACK, NOTIFY, PUBLISH, SUBSCRIBE
Supported: precondition, 100rel, timer, path, replaces
Content-Length: 0
至此注册流程结束。
加密密码生成
从上述注册过程中就可以发现,密码并没有明文传输,而是X-Lite加密后发送至FreeSWITCH,FreeSWITCH以相同的方式加密后并比对,以完成对X-Lite的认证。下面笔者来说一下加密密码是如何生成的。
HA1:
首先我们需要计算HA1。HA1是计算username:relam:password
字符串的MD5值。 除了密码,其它字段从上述信令中我们能找到,就是计算1015:www.freeswitch
.com:1234的MD5值(默认密码为1234)。
HA1 = md5("1015:www.freeswitch.com:1234") = fe7632dead0ef79b9f1b0bde9d71ac7a
HA2:
然后我们计算HA2。HA2是计算method:uri
字符串的MD5值。也就是计算REGISTER:sip:www.freeswitch.com
的MD5值。
HA2 = md5("REGISTER:sip:www.freeswitch.com") = 357860fa5d775b1ec660c952831a065f
加密密码最终根据HA1和HA2生成最终的MD5值。即计算HA1:nonce:nc:cnonce:qop:HA2
字符串的MD5值。从上述信令中找到相关字段。
MD5 = md5("fe7632dead0ef79b9f1b0bde9d71ac7a:3135ef65-3466-4f70-8035-ec70ff10ae75:00000001:be28d6ed344661886ad93c8504358936:auth:357860fa5d775b1ec660c952831a065f") = d702aa1a84ecc11dc83f4a7c4e56c39a