1.
2.
3.
UA之间的认证
图1-1 UA之间的认证流程
UA和Proxy之间的认证
图1-2 UA和Proxy之间的认证流程
4.
注:只讲述重要字段,细节查看RFC2617。
具体为401中的WWW-Authenticate应答头域,相对应的为请求的Authorization头域;407中的Proxy-Authenticate头域,相对应的是请求的Proxy-Authorization头域。
a)
这个头域值包含了至少一个表明认证方式和适用realm的参数的拒绝原因。
如:
i.
realm字串单独定义被保护的区域。Realm字串必须是全局唯一的。我们强调这个realm字串必须包含一个主机名或者域名。Realm字串应当是一个可读的能够展示给用户的字串。
通常,SIP认证对于特定realm(一个保护区域)是有意义的。因此,对于Digest认证来说,每一个类似的保护区域都有自己的用户名和密码集合。
ii.
服务器端指定的数据字符,它应在每个401回应产生时,被唯一地创建。建议该字符以base64方式或16进制方式出现。另外,该字符在标题行中传递时是在引号内的,因此允许使用双引号字符。
iii.
一个标志,用来指示客户端先前的请求因其nonce值过期而被拒绝。如果stale是TRUE(大小写敏感),客户端可能希望用新的加密回应重新进行请求,而不用麻烦用户提供新的用户名和口令。服务器端只有在收到的请求nonce值不合法,而该nonce对应的摘要(digest)是合法的情况下(即客户端知道正确的用户名/口令),才能将stale置成TRUE值。如果stale是FALSE或其它非TRUE值,或者其stale域不存在,说明用户名、口令非法,要求输入新的值。
iv.
Algorithm是个字符串,用来指示用来产生摘要及校验和的算法对。如果该域没指定,则认为是“MD5“算法。如果该域指定的算法无法理解,该质询(challenge)将被忽略。
v.
“auth”表示鉴别方式;“auth-int”表示鉴别保护的完整性。
vi.
由服务器指定的字符串,客户端不能改动它,如果并发请求的URI也指向同一个受保护区间,则该信息将被加在这些请求的授权标题域中返给服务器。建议采用base64或16进制的字符串。
b)
该头域包含了具有这个UA到请求的资源所在的realm(区域)的信任书和所需要的认证支持的参数和重现保护的参数。
例子:
如果服务器对特定请求没有要求认证或对于特定realm没有对应的认证信息,那么使用缺省的用户名,”anonymous”,并且这个用户名没有密码(密码是””)。
根据RFC2617,合法的回应包含对用户名、口令、给定nonce值、SIP方法、请求URI的校验和(checksum,缺省是MD5的校验和)。
i.
是个字符串,由32个经过计算的16进制数字组成,用来证明用户是否知道口令。
ii.
当qop指示发送了,该指示必须要指定,而当服务器端没有在WWW-鉴别(WWW- Authenticate)标题域中添加qop指示时,该指示一定不能指定。cnonce-value是客户端提供的字符串,它由客户端和服务器共同使用,用来避免选择纯文本攻击、提供共同鉴别、提供某些消息的完整性保护。
5.
128位的MD5摘要由32个可打印的ASCII码字符表示。128位摘要中的位按其重要性由高到低转换,在某个时刻每4位可用下面的ASCII表示。每4位都可用16进制字符‘0123456789abcdef’表示,也就是说,二进制0000由字符‘0’表示;0001由字符‘1’表示,以后如此类推,1111用‘f’表示。
在本文中,用KD(secret,data)来表示摘要算法,其中data指数据,secret表示采用的方法.如果表示校验和算法时,data要写成H(data);而unq(X)表示将带引号字符串的引号去掉。
简单来说,response =
H(H(username:realm:password):nonce:cnonce:H(requestMothod:request-URI))
以下为详细的计算规则.
对于"MD5" 和"MD5-sess" 算法:
H():hash函数
H(data) = MD5(data)
和
KD(secret, data) = H(concat(secret, ":", data))
也就是说,摘要(digest)就是对secret与data通过冒号连接一起的结果进行MD5运算。而"MD5-sess"算法则允许其它第三方服务器参与鉴别。
a)
如果”qop”值是"auth" 或"auth-int":
request-digest &#61; <">
":" unq(cnonce-value)
":" unq(qop-value)
":" H(A2)
) <">
如果”qop”指示没有给出&#xff08;与RFC2069保持兼容性&#xff09;&#xff1a;
request-digest &#61;<">
) <">
A1及A2的定义在下面。
b)
如果算法&#xff08;"algorithm"&#xff09;值是”MD5”或没有指定&#xff0c;则A1是&#xff1a;
A1 &#61; unq(username-value) ":" unq(realm-value) ":" passwd
其中
passwd &#61;
如果"algorithm"值是"MD5-sess"&#xff0c;则A1只要计算一次&#xff0c;即当客户端发出第一个请求&#xff0c;并从服务器收到WWW-鉴别&#xff08;WWW-Authenticate&#xff09;质询&#xff08;challenge&#xff09;时计算。它使用该质询中的服务器的nonce&#xff0c;则用来构建A1的第一个客户端nonce值应为&#xff1a;
A1 &#61; H( unq(username-value) ":" unq(realm-value)
":" passwd )
":" unq(nonce-value) ":" unq(cnonce-value)
上式为并发请求和回应的鉴别产生一个‘会话密钥’&#xff08;session key&#xff09;&#xff0c;该密钥对于每个‘鉴别会话’&#xff08;authentication session&#xff09;都是不同的&#xff0c;这样&#xff0c;就限制了使用任何一个密钥进行哈希处理的次数。
c)
如果”qop”值是”auth”或者没给出&#xff0c;则A2&#xff1a;
A2 &#61; Method ":" digest-uri-value
如果"qop"值是"auth-int", 则A2&#xff1a;
A2 &#61; Method ":" digest-uri-value ":" H(entity-body)
d)
注意&#xff0c;许多指示的取值&#xff0c;如”username-value”等&#xff0c;被定义成带引号的字符串&#xff08;quoted-string&#xff09;。而实际上&#xff0c;”unq”注释则表示在生成字符串A1时&#xff0c;去掉其外部的引号。因而&#xff0c;如当授权标题包括该域&#xff0c;如&#xff1a;
username&#61;"Mufasa", realm&#61;myhost&#64;testrealm.com
则表示用户Mufasa的口令是"Circle Of Life"&#xff0c;这样H&#xff08;A1&#xff09;就可表示成
H&#xff08;Mufasa:myhost&#64;testrealm.com:Circle Of Life&#xff09;&#xff0c;注意&#xff0c;在摘要字符串中没有引号。
注意&#xff0c;在摘要函数H&#xff08;&#xff09;中的字符串中不允许出现空格&#xff0c;除非空格出现在带引号的字符串内或者用以标记字符串摘要的实体主体中。例如&#xff0c;上面出现的字符串A1必须是
Mufasa:myhost&#64;testrealm.com:Circle Of Life
在冒号的两边都不可以有空格&#xff0c;但是允许口令单词之间出现空格&#xff08;Circle&#43;SP&#43;Of&#43;SP&#43;Life&#xff09;。同样&#xff0c;其它由H&#xff08;&#xff09;摘要的字符串也不能在用于域间分隔的冒号两边加空格&#xff0c;除非空格在引号内或被摘要的实体主体内。
同样要注意的是&#xff0c;如果应用了完整性保护&#xff08;integrity protection&#xff09;&#xff0c;即qop&#61;auth-int&#xff0c;则H&#xff08;实体-主体&#xff09;就是实体主体的哈希值&#xff0c;而不是消息主体的哈希值&#xff0c;该值在发送方进行任何传输编码前计算&#xff0c;之后&#xff0c;被接收方删除。
6.MD5值计算方式
RFC2617定义了两种加密的方式&#xff0c;一种是BASE64的&#xff0c;另一种是MD5加密&#xff0c;大多SIP协议栈都采用的后者&#xff0c;可能是出于安全的考虑&#xff0c;因为MD5是不可逆的。
对于MD5的方式&#xff0c;RFC2617有提供一个example的实现&#xff0c;有源代码&#xff0c;但奇怪的是我将它的源代码复制下来&#xff0c;运行后发现&#xff0c;计算RFC2617中的例子时得到的MD5值是对的&#xff0c;但我自己架的3CX Server和PBX却总是work不起来&#xff0c;我用x-lite去注册&#xff0c;然后抓包比对发现原因是我计算出来到MD5值Response不对&#xff0c;这让我很是郁闷&#xff0c;后来比对发现两者之间有些差别&#xff0c;例子中有Cnonce值&#xff0c;但我抓的包中没有&#xff0c;于是我将Cnonce置为NULL计算&#xff0c;发现还是不对&#xff0c;没辙了&#xff0c;只好去研究它们的计算方法。
后来发现SIP中验证的MD5值是通过如下方式得到的&#xff1a;
step1:caculate username:realm:password MD5 value to get HA1
step2:caculate method:uri MD5 value to get HA2
step3:caculate HA1:nonce:HA2 MD5 value, it&#39;s the result
对比源代码&#xff0c;我注掉一段code后&#xff0c;发现得到了正确的MD5值&#xff0c;如下&#xff1a;