Chinaunix首页 | 论坛 | 博客
  • 博客访问: 195377
  • 博文数量: 31
  • 博客积分: 2595
  • 博客等级: 少校
  • 技术积分: 334
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-28 16:03
个人简介

知行合一

文章分类

全部博文(31)

文章存档

2015年(1)

2014年(1)

2010年(9)

2009年(20)

我的朋友

分类: 系统运维

2009-07-28 21:41:56

注:以下文章如需转载,请注明所属作者,转载地址,谢谢!

第五章:用MySQL添加认证(Adding Authentication with MySQL

在这一章中我们将学到如何使用几种数据库后端来对SIP请求进行鉴定并提供诸如位置和别名表等数据的持续性。最主要的是,我们将使用MySQL来做每一件事。这一章分为两个部分。第一个部分,我们将学到如何实现认证,第二部分我们将学到如何处理不同方向的通话。

这一章的最后,你将能够:

l        配置MySQL来对SIP设备进行认证

l        使用openserctl工具来实现基本的操作,如添加和删除用户

l        改变脚本openser.cfg来配置MySQL认证

l        实现订阅列表的连续性

l        实现位置列表的连续性

l        重启服务器但是不丢失位置记录

l        正确的处理inbound-to-inboundinbound-to-outboundoutbound-to-inbound,和outbound-to-outbound会话

l        正确的处理CANCEL请求

我们在哪儿?(Where Are We?)

现在,我们仍然将集中精力于SIP代理上。然而,我们将包含一个新的部件,数据库。OpenSER可以使用MySQLPostgreSQL。在这本书中,我们选择的是MySQL。到目前为止,它是OpenSER使用最多的数据库。

AUTH_DB模块(The AUTH_DB Module

以数据库为基础的认证是由AUTH_DB模块实现的。其他类型的认证,如radiusdiameter可以分别使用AUTH_RADIUSAUTH_DIAMETER来实现。AUTH_DB和诸如MySQLPostgreSQL等数据库模块一起工作。AUTH_DB有一些参数没有在脚本中明确的声明。让我们看看AUTH_DB模块的默认参数。


ATUH_DB模块会导出两个函数。

www_authorize(realm, table)

这个函数在REGISTER的认证中被使用,和RFC2617保持一致。

proxy_authorize(realm, table)

这个函数按照RFC2617non-REGISTER请求的证书进行验证。如果验证成功,则该证书将被标记为已认证。

如果你的服务器是请求的终点,那么你必须使用www_authorize函数。而当请求的最终目的地不是你的服务器,那么则使用proxy_authorize函数,然后你要对请求进行前转,这时,服务器实际上是作为代理在工作。

www_authorizeproxy_authorize的不同使用之处就在于请求的终点是否是你的服务器(REGISTER)。

REGISTER认证顺序(The REGISTER Authentication Sequence

脚本应该对REGISTERINVITE消息进行认证。在修改openser.cfg脚本之前,让我们先展示这是如何发生的。当OpenSER收到REGISTER消息时,它先检查其是否有Authorize头域。如果没有找到,它会请求UAC的证书并退出。

UAC收到请求后,向其再次发送REGISTER消息,此时的消息中带有Authorize头域。


注册过程(ngrep抓的包)(Register SequencePackets Captured by ngrep))

注册过程可以从下面的抓包中看到:

U 192.168.1.119:29040 -> 192.168.1.155:5060

REGISTER sip:192.168.1.155 SIP/2.0.

Via: SIP/2.0/UDP 192.168.1.119:29040;branch=z9hG4bK-d87543-13517a5a8218ff45-1--d87543-;rport.

Max-Forwards: 70.

Contact: .

To: "1000".

From: "1000";tag=0d10cc75.

Call-ID:

e0739d571d287264NjhiZjM2N2UyMjhmNDViYTgzY2I4ODMxYTVlZTY0NDc..

CSeq: 1 REGISTER.

WWW-Authenticate: Digest realm="192.168.1.155", nonce="46263864b3abb96a423a7ccf052fa68d4ad5192f".

Server: OpenSER (1.2.0-notls (i386/linux)).

Content-Length: 0.

U 192.168.1.119:29040 -> 192.168.1.155:5060

REGISTER sip:192.168.1.155 SIP/2.0.

Via: SIP/2.0/UDP 192.168.1.119:29040;branch=z9hG4bK-d87543-da776d09bd6fcb65-1--d87543-;rport.

Max-Forwards: 70.

Contact: .

To: "1000".

From: "1000";tag=0d10cc75.

Call-ID: e0739d571d287264NjhiZjM2N2UyMjhmNDViYTgzY2I4ODMxYTVlZTY0NDc..

CSeq: 2 REGISTER.

Expires: 3600.

Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO.

User-Agent: X-Lite release 1003l stamp 30942.

Content-Length: 0.

U 192.168.1.155:5060 -> 192.168.1.119:29040

SIP/2.0 401 Unauthorized.

Via: SIP/2.0/UDP 192.168.1.119:29040;branch=z9hG4bK-d87543-13517a5a8218ff45-1--d87543-;rport=29040.

To: "1000";tag=329cfeaa6ded039da25ff8cbb8668bd2.41bb.

From: "1000";tag=0d10cc75.

Call-ID: e0739d571d287264NjhiZjM2N2UyMjhmNDViYTgzY2I4ODMxYTVlZTY0NDc..

CSeq: 1 REGISTER.

WWW-Authenticate: Digest realm="192.168.1.155",nonce="46263864b3abb96a423a7ccf052fa68d4ad5192f".

Server: OpenSER (1.2.0-notls (i386/linux)).

Content-Length: 0.

U 192.168.1.119:29040 -> 192.168.1.155:5060

REGISTER sip:192.168.1.155 SIP/2.0.

Via: SIP/2.0/UDP 192.168.1.119:29040;branch=z9hG4bK-d87543-da776d09bd6fcb65-1--d87543-;rport.

Max-Forwards: 70.

Contact: .

To: "1000".

From: "1000";tag=0d10cc75.

Call-ID: e0739d571d287264NjhiZjM2N2UyMjhmNDViYTgzY2I4ODMxYTVlZTY0NDc..

CSeq: 2 REGISTER.

Expires: 3600.

Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO.

User-Agent: X-Lite release 1003l stamp 30942.

Authorization: Digest username="1000",realm="192.168.1.155",nonce="46263864b3abb96a423a7ccf052fa68d4ad5192f",uri="sip:192.168.1.155",response="d7b33793a123a69ec12c8fc87abd4c03",algorithm=MD5.

Content-Length: 0.

U 192.168.1.155:5060 -> 192.168.1.119:29040

SIP/2.0 200 OK.

Via: SIP/2.0/UDP 192.168.1.119:29040;branch=z9hG4bK-d87543-da776d09bd6fcb65-1--d87543-;rport=29040.

To: "1000";tag=329cfeaa6ded039da25ff8cbb8668bd2.c577.

From: "1000";tag=0d10cc75.

Call-ID: e0739d571d287264NjhiZjM2N2UyMjhmNDViYTgzY2I4ODMxYTVlZTY0NDc..

CSeq: 2 REGISTER.

Contact: ;expires=3600.

Server: OpenSER (1.2.0-notls (i386/linux)).

Content-Length: 0.

注册过程的代码片段(Register Sequence Code Snippet

现在让我们看看这个过程在openser.cfg脚本中是如何写的吧:

if (method=="REGISTER") {

# Uncomment this if you want to use digest authentication

if (!www_authorize("", "subscriber")) {

www_challenge("", "0");

exit;

};

save("location");

exit;

}

在上面的过程中,第一次传的REGISTER包没有被www_authorize函数认证。然后,www_challenge语句被调用。它发送了“401 Unauthorized”包,这个包按照摘要认证方法(digest authentication scheme)包含了认证请求。UAC第二次传的REGISTER包添加了Authorize头域,然后,save”location”)函数被调用用来保存AORMySQL的位置表。

INVITE认证过程(The INVITE Authentication Sequence

相对的则是一通普通通话的INVITE认证过程。代理服务器总是会对第一个INVITE请求进行响应,使用的是”407 Proxy Authentication Required”消息。这个消息包含了Authorize头域,含有关于摘要认证的信息,如realmnonce。一旦UAC收到这个消息,它就会立即发送一条新的INVITE消息。现在,Authorize中包含了可以使用MD5算法进行计算的摘要,包括usernamepasswordrealm,和nonce。如果在服务器上使用与之相同的参数进行计算的摘要和UAC传递的摘要相符时,用户得到认证。


INVITE过程的抓包(INVITE Sequence Packet Capture

我们用ngrep抓了一套INVITE认证过程的包。这个过程能够帮助你理解上面的图。为了避免列的过长,我们没有将SDP头的内容一起附上。

U 192.168.1.169:5060 -> 192.168.1.155:5060

INVITE sip:1000@192.168.1.155 SIP/2.0.

Via: SIP/2.0/UDP 192.168.1.169;branch=z9hG4bKf45d977e65cf40e0.

From: ;tag=a83bebd75be1d88e.

To: .

Contact: .

Supported: replaces.

Call-ID: 8acb7ed7fc07c369@192.168.1.169.

CSeq: 39392 INVITE.

User-Agent: TMS320V5000 TI50002.0.8.3.

Max-Forwards: 70.

Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE.

Content-Type: application/sdp.

Content-Length: 386.

(sdp header striped off).

U 192.168.1.155:5060 -> 192.168.1.169:5060

SIP/2.0 407 Proxy Authentication Required.

Via: SIP/2.0/UDP 192.168.1.169;branch=z9hG4bKf45d977e65cf40e0.

From: ;tag=a83bebd75be1d88e.

To: ;tag=329cfeaa6ded039da25ff8cbb8668bd2.b550.

Call-ID: 8acb7ed7fc07c369@192.168.1.169.

CSeq: 39392 INVITE.

Proxy-Authenticate: Digest realm="192.168.1.155", nonce="4626420b4b162ef84a1a1d3966704d380194bb78".

Server: OpenSER (1.2.0-notls (i386/linux)).

Content-Length: 0.

U 192.168.1.169:5060 -> 192.168.1.155:5060

ACK sip:1000@192.168.1.155 SIP/2.0.

Via: SIP/2.0/UDP 192.168.1.169;branch=z9hG4bKf45d977e65cf40e0.

From: ;tag=a83bebd75be1d88e.

To: ;tag=329cfeaa6ded039da25ff8cbb8668bd2.b550.

Contact: .

Call-ID: 8acb7ed7fc07c369@192.168.1.169.

CSeq: 39392 ACK.

User-Agent: TMS320V5000 TI50002.0.8.3.

Max-Forwards: 70.

Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE.

Content-Length: 0.

U 192.168.1.169:5060 -> 192.168.1.155:5060

INVITE sip:1000@192.168.1.155 SIP/2.0.

Via: SIP/2.0/UDP 192.168.1.169;branch=z9hG4bKcdb4add5db72d493.

From: ;tag=a83bebd75be1d88e.

To: .

Contact: .

Supported: replaces.

Proxy-Authorization: Digest username="1001", realm="192.168.1.155", algorithm=MD5, uri="sip:1000@192.168.1.155", nonce="4626420b4b162ef84a1a1d3966704d380194bb78", response="06736c6d7631858bb1cbb0c86fb939d9".

Call-ID: 8acb7ed7fc07c369@192.168.1.169.

CSeq: 39393 INVITE.

User-Agent: TMS320V5000 TI50002.0.8.3.

Max-Forwards: 70.

Allow: INVITE,ACK,CANCEL,BYE,NOTIFY,REFER,OPTIONS,INFO,SUBSCRIBE.

Content-Type: application/sdp.

Content-Length: 386.

(sdp header striped off)

INVITE Code Snippet

In the code below, the SIP proxy will challenge the user for

credentials on any request different from REGISTER. We consume the credentials after authentication, for security reasons, to avoid sending encrypted material ahead.

if (!proxy_authorize("","subscriber")) {

proxy_challenge("","0");

exit;

};

consume_credentials();

lookup("aliases");

if (!uri==myself) {

append_hf("P-hint: outbound alias\r\n");

route(1);

};

# native SIP destinations are handled using our USRLOC DB

if (!lookup("location")) {

sl_send_reply("404", "Not Found");

exit;

};

append_hf("P-hint: usrloc applied\r\n");

};

route(1);

摘要认证(Digest Authentication

摘要认证的基础是RFC2617中的”HTTP Basic and Digest Access Authentication”。我们这一章节的目的是介绍一个带有摘要认证的系统的要素。它不是对于SIP的所有可能的安全性问题的回答,但确实是一种可以保护在网络传输中的用户名和密码的好方法。


摘要方法是一中简单的请求响应机制(challenge-response mechanism)。使用nonce值向UA发出请求。一个有效的响应包含有所有参数的一个校验和(checksum)。因此,密码从不以简单的文本形式进行传输。

WWW-Authenticate响应头(WWW-Authenticate Response Header

如果服务器没有收到带有有效Authorize头域的REGISTERINVITE请求,那么它会返回一个带有WWW-Authenticate头域的”401 unauthorized”消息。这个头包含一个realm和一个nonce

认证请求头(The Authorization Request Header

我们希望用户能够再试一次,但是要带上Authorize头域。该头要包含用户名,realmnonce(由server提供),uri,一个32位的十六进制数,还有一种认证方法(此例中是MD5)。这种响应是用户使用一种特定的算法产生的校验和。

QOP——保护质量(QOP ------- Quality of Protection

qop参数表明了用户应用到该消息上的保护的质量。如果出现了这个参数,那么它的值要是服务器支持的所有可选值之一。这些选择在WWW-Authenticate头域中表明。这些值会影响摘要的计算。之所以有这条指令,是为了和RFC2809的最小实现保持兼容。

你可以在两个函数中对该参数进行配置,分别是www_challenge(realm, qop)proxy_challenge(realm, qop)。如果被配成1,那么服务器就会要求有qop参数。总是使用qop=1会帮助你避免’replay”攻击。然而,一些用户对于qop会不兼容。对于摘要认证的详细描述见RFC2617

阅读(3883) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

zhaiqi1632009-07-29 11:40:42

谢谢鼓励,您的需求我会注意,就是更新速度太慢的问题可能因为工作的原因有点困难,不过我会尽量加快速度。

chinaunix网友2009-07-29 10:53:36

感谢翻译!正在找寻这类资料!谢谢!我E文不好!你帮大忙了! 说点缺点,就是更新速度太慢了!呵呵!每天都期待看到新章节! 希望在更新的时候也提供doc或者pdf等形式下载! 最后,希望你坚持下去啊!