SIP鉴权过程

在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