SIP協議詳解-6

由於MIME包體是在”inner”消息中的,實現中通常會加密MIME指定的頭域,包括:MIME-Version,Content-Type,Content-Length, Content-Language, Content-Encoding, 和Content-Disposition。”outer”消息會爲S/MIME包體使用適當的MIME頭域。這些頭域(和他們開始的任何MIME包體)在SIP消息中,應當作爲普通的MIME頭域和包體
接收。

對下邊這些頭域的加密並不是特別有用: Min-Expires, Timestamp, Authorization, Priority, 和 WWWAuthenticate。這類頭域包含了那些能夠被proxy服務器所更改的頭域(在前邊章節有講述)。如果這些頭域不出現在”outer”消息中,那麼UA應當不在”inner”消息中包含這些頭域。如果UA在加密的包體中接收到這些頭域,應當忽略到這些加密的值。

注意,SIP的擴展可能會定義附加的頭域;那麼這些擴展的作者應當描述這些頭域的完整性和機密性特性。如果一個SIP UA遇到了一個不認識的頭域,並且產生了一個完整性衝突,它必須忽略掉這個頭域。

23.4.2 隧道的完整性和身份認證
通過S/MIME包體的SIP消息隧道可以提供SIP頭域的完整性保證,只要發送方把這個包整個打包放在用CMS分離簽名的”message/sip” MIME包體中。

假設那個”message/sip”包體包含了最基本的對話要素(最小集合)(To, From, Call-ID, CSEq),並且一個簽名的MIME包體可以提供優先的身份認證。在這個特別的最小集合上,如果接受方不認識用於簽名MIME包體的信任狀,並且不能被檢驗,那麼在同一個信任狀擁有者所初始化的會話中,這個信任狀擁有者可以稍後發送一個在會話中的請求,包含這個簽名來進行確認。如果簽名MIME包體的接受方選擇信任這個信任書(他們可以檢驗信任書,他們已經從信任列表中檢查了,或者他們經常使用這個信任書),那麼這個簽名就和這個信任書的主題有着相同的身份一致性。

爲了排出可能的對實體包頭域增加減少的相關困惑,發送方應當把請求的所有頭域放在簽名的包體中。任何需要完整性保護的包體都必須添加到”inner”消息中。

如果有一個簽名包體的消息中包含一個Date頭域,接受方應當比較它自己的內部時鐘和這個頭域值。如果檢測到了時差(比如超過1個小時或者更多),UA應當警告使用者,並且提示這個可能是安全隱患。

如果接受方檢測到消息的完整性破壞了,如果是這個消息是請求,那麼應當使用403(Forbidden)來拒絕這個請求,或者終止現存的對話。UA應當提示用戶這個情況,並且要求明確的操作指示。

下邊是一個使用隧道”message/sip”的例子:

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
To: Bob <sip:[email protected]>
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Max-Forwards: 70
Date: Thu, 21 Feb 2002 13:02:03 GMT
Contact: <sip:[email protected]>
Content-Type: multipart/signed;
protocol="application/pkcs7-signature";
micalg=sha1; boundary=boundary42
Content-Length: 568

--boundary42
Content-Type: message/sip

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
To: Bob <[email protected]>
From: Alice <[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Max-Forwards: 70
Date: Thu, 21 Feb 2002 13:02:03 GMT
Contact: <sip:[email protected]>
Content-Type: application/sdp
Content-Length: 147

v=0
o=UserA 2890844526 2890844526 IN IP4 here.com
s=Session SDP
c=IN IP4 pc33.atlanta.com
t=0 0
m=audio 49172 RTP/AVP 0
a=rtpmap:0 PCMU/8000

--boundary42
Content-Type: application/pkcs7-signature; name=smime.p7s
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=smime.p7s;
handling=required
ghyHhHUujhJhjH77n8HHGTrfvbnj756tbB9HG4VQpfyF467GhIGfHfYT6
4VQpfyF467GhIGfHfYT6jH77n8HHGghyHhHUujhJh756tbB9HGTrfvbnj
n8HHGTrfvhJhjH776tbB9HG4VQbnj7567GhIGfHfYT6ghyHhHUujpfyF4
7GhIGfHfYT64VQbnj756

--boundary42-


23.4.3 隧道加密
把”message/sip”MIME包體用CMS EnvelopedData消息S/MIME包體進行加密是值得的,但是在實踐中,大部分頭域都是用於網絡的;而通常使用S/MIME進行的加密都是加密類似SDP的消息體的,而不是消息頭的。有一部分頭域的信息,比如Subject或者Organization或許需要端到端的安全保證。以後的SIP應用可能會定義其他的頭域,這些頭域也或許需要端到端的安全保證。

另一個加密頭域的可能的應用是選擇性匿名。可以構造一個沒有個人信息的From頭域(比如sip:[email protected])。不過,第二個From頭域包含了真實的請求者的address-of-record信息,並且加密存放在”message/sip”MIME包體中,並且只會在對話的對方節點被看到。

注意如果這個機制用於匿名,那麼將接受方將不再用From頭域來作爲密鑰組的索引,並且也不用於從密鑰組查詢合適的發送方的S/MIME密鑰。這個消息必須首先被解密,並且”inner”From頭域必須當作一個索引。

爲了提供端到端的完整性,加密的”message/sip”MIME包體應當由發送方簽名。這個創建了一個包含一個加密包體和一個簽名的”multipart/signed” MIME包體,包體類型都是”application/pkcs7-mime”.。

在下邊這個例子中,是一個加密和簽名的消息,在*括起來的文字是加密的:

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
To: Bob <sip:[email protected]>
From: Anonymous <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Max-Forwards: 70
Date: Thu, 21 Feb 2002 13:02:03 GMT
Contact: <sip:pc33.atlanta.com>
Content-Type: multipart/signed;
protocol="application/pkcs7-signature";
micalg=sha1; boundary=boundary42
Content-Length: 568

--boundary42
Content-Type: application/pkcs7-mime; smime-type=enveloped-data;
name=smime.p7m
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=smime.p7m
handling=required
Content-Length: 231

******************************************************************************
* Content-Type: message/sip                                    *
*                                                            *
* INVITE sip:[email protected] SIP/2.0                            *
* Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8    *
* To: Bob <[email protected]>                                    *
* From: Alice <[email protected]>;tag=1928301774                *
* Call-ID: a84b4c76e66710                                    *
* CSeq: 314159 INVITE                                        *
* Max-Forwards: 70                                            *
* Date: Thu, 21 Feb 2002 13:02:03 GMT                        *
* Contact: <sip:[email protected]>                        *
*                                                            *
* Content-Type: application/sdp                                *
*                                                            *
* v=0                                                        *
* o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com            *
* s=Session SDP                                            *
* t=0 0                                                        *
* c=IN IP4 pc33.atlanta.com                                    *
* m=audio 3456 RTP/AVP 0 1 3 99                                *
* a=rtpmap:0 PCMU/8000                                        *
******************************************************************************

--boundary42
Content-Type: application/pkcs7-signature; name=smime.p7s
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=smime.p7s;
handling=required

ghyHhHUujhJhjH77n8HHGTrfvbnj756tbB9HG4VQpfyF467GhIGfHfYT6
4VQpfyF467GhIGfHfYT6jH77n8HHGghyHhHUujhJh756tbB9HGTrfvbnj
n8HHGTrfvhJhjH776tbB9HG4VQbnj7567GhIGfHfYT6ghyHhHUujpfyF4
7GhIGfHfYT64VQbnj756

--boundary42-

24 例子

在下邊這個例子中,由於簡略介紹的關係我們經常省略消息體和對應的Content-Length和Content-Type頭域。

24.1 註冊
Bob在啓動的時候進行註冊。這個消息流在圖9中展示。注意對於註冊服務來說,通常需要認證,而且不像下邊描述的這樣簡單。











圖9: SIP 註冊例子

F1 REGISTER Bob -> Registrar
REGISTER sip:registrar.biloxi.com SIP/2.0
Via: SIP/2.0/UDP bobspc.biloxi.com:5060;branch=z9hG4bKnashds7
Max-Forwards: 70
To: Bob <sip:[email protected]>
From: Bob <sip:[email protected]>;tag=456248
Call-ID: 843817637684230@998sdasdh09
CSeq: 1826 REGISTER
Contact: <sip:[email protected]>
Expires: 7200
Content-Length: 0

註冊會在2小時後超時。註冊服務器迴應一個200OK:
F2 200 OK Registar -> Bob
SIP/2.0 200 OK
Via: SIP/2.0/UDP bobspc.biloxi.com:5060;branch=z9hG4bKnashds7
;received=192.0.2.4
To: Bob <sip:[email protected]>;tag=2493k59kd
From: Bob <sip:[email protected]>;tag=456248
Call-ID: 843817637684230@998sdasdh09
CSeq: 1826 REGISTER
Contact: <sip:[email protected]>
Expires: 7200
Content-Length: 0

24.2 建立會話
這個例子包括了4節描述的建立會話的細節。消息流在圖1中展示了。注意這些消息流展示了頭域的最小集合--一般來說還需要包含一些其他頭域,比如Allow和Supported頭域。

F1 INVITE Alice -> atlanta.com proxy

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
Max-Forwards: 70
To: Bob <sip:[email protected]>
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:[email protected]>
Content-Type: application/sdp
Content-Length: 142

(Alice’s SDP not shown)

F2 100 Trying atlanta.com proxy -> Alice

SIP/2.0 100 Trying
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:[email protected]>
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Content-Length: 0

F3 INVITE atlanta.com proxy -> biloxi.com proxy

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
Max-Forwards: 69
To: Bob <sip:[email protected]>
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:[email protected]>
Content-Type: application/sdp
Content-Length: 142

(Alice’s SDP not shown)

F4 100 Trying biloxi.com proxy -> atlanta.com proxy

SIP/2.0 100 Trying
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:[email protected]>
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Content-Length: 0

F5 INVITE biloxi.com proxy -> Bob

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
Max-Forwards: 68
To: Bob <sip:[email protected]>
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:[email protected]>
Content-Type: application/sdp
Content-Length: 142

(Alice’s SDP not shown)

F6 180 Ringing Bob -> biloxi.com proxy

SIP/2.0 180 Ringing
Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
;received=192.0.2.3
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:[email protected]>;tag=a6c85cf
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
Contact: <sip:[email protected]>
CSeq: 314159 INVITE
Content-Length: 0

F7 180 Ringing biloxi.com proxy -> atlanta.com proxy

SIP/2.0 180 Ringing
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:[email protected]>;tag=a6c85cf
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
Contact: <sip:[email protected]>
CSeq: 314159 INVITE
Content-Length: 0

F8 180 Ringing atlanta.com proxy -> Alice

SIP/2.0 180 Ringing
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:[email protected]>;tag=a6c85cf
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
Contact: <sip:[email protected]>
CSeq: 314159 INVITE
Content-Length: 0

F9 200 OK Bob -> biloxi.com proxy

SIP/2.0 200 OK
Via: SIP/2.0/UDP server10.biloxi.com;branch=z9hG4bK4b43c2ff8.1
;received=192.0.2.3
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:[email protected]>;tag=a6c85cf
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:[email protected]>
Content-Type: application/sdp
Content-Length: 131

(Bob’s SDP not shown)

F10 200 OK biloxi.com proxy -> atlanta.com proxy

SIP/2.0 200 OK
Via: SIP/2.0/UDP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1
;received=192.0.2.2
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:[email protected]>;tag=a6c85cf
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:[email protected]>
Content-Type: application/sdp
Content-Length: 131

(Bob’s SDP not shown)

F11 200 OK atlanta.com proxy -> Alice

SIP/2.0 200 OK
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8
;received=192.0.2.1
To: Bob <sip:[email protected]>;tag=a6c85cf
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 INVITE
Contact: <sip:[email protected]>
Content-Type: application/sdp
Content-Length: 131

(Bob’s SDP not shown)

F12 ACK Alice -> Bob

ACK sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds9
Max-Forwards: 70
To: Bob <sip:[email protected]>;tag=a6c85cf
From: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 314159 ACK
Content-Length: 0

在Alice和Bob之間的媒體會話現在建立了。Bob首先掛機。注意Bob的SIP電話維持它自己的Cseq號碼空間,在這裏,是231開始的。由於Bob發起請求,那麼To和From URI和tags交換了。

F13 BYE Bob -> Alice

BYE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 192.0.2.4;branch=z9hG4bKnashds10
Max-Forwards: 70
From: Bob <sip:[email protected]>;tag=a6c85cf
To: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 231 BYE
Content-Length: 0

F14 200 OK Alice -> Bob

SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.0.2.4;branch=z9hG4bKnashds10
From: Bob <sip:[email protected]>;tag=a6c85cf
To: Alice <sip:[email protected]>;tag=1928301774
Call-ID: a84b4c76e66710
CSeq: 231 BYE
Content-Length: 0

這個SIP呼叫流程文檔[40]包含了SIP消息的更多例子。

25 SIP協議的BNF範式
本協議中定義的機制都用文本和Backus-Naur Form(BNF)範式定義(RFC2234[10])。6.1節和RFC2234定義了一個本文檔使用的基本核心規則,這裏就不贅述了。實現者需要熟悉RFC2234協議,這樣才能理解整理定義的規範。某些基本規則是用大寫字母表示的,比如SP,LWS,HTAB,CRLF,DIGIT,ALPHA,等等。尖括號定義了規則的名字。

方括號的使用是在語法上可選的。在這裏用於特定參數是可選的語義提示。

25.1 基本規則
下列貫穿本規範的規則是用於描述基本的語法結構。US-ASCII碼字符集是在ANSI X3.4-1986中定義的。

alphanum = ALPHA/DIGIT

部分規則是和RFC2396[5]中合併使用的,但是依據RFC2234[10]做了更新,這些包括:

reserved = ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","

unreserved = alphanum / mark
mark = "-" / "_" / "." / "!" / "˜" / "*" / "’" / "(" / ")"

escaped = "%" HEXDIG HEXDIG

SIP頭域值可以摺疊成爲多行,如果每行的開始是一個空格或者一個水平製表符(就是Tab鍵啦)。所有的線形空白,包含摺疊的空白,和SP有着同樣的語義(SP就是空格啦)。一個接受方在處理頭域值之前或者轉發消息到下行隊列之前,可以把任何線形空白當作一個單個SP處理。這個和RFC2616[8]中描述的HTTP/1.1處理方法完全一樣。當線形空白是可選的時候,SWS構造就需要了,通常在兩個符號和分隔符之間存在:

LWS = [*WSP CRLF] 1*WSP ; linear whitespace
SWS = [LWS] ; sep whitespace

爲了把頭域名和頭域值分開,就需要使用冒號,根據上邊的規則,允許在冒號之前有空白,但是不允許有行分隔符,並且允許在冒號之後有空白,或者行分隔符。HCOLON有如下定義:

HCOLON = *( SP / HTAB ) ":" SWS

TEXT-UTF8規則只用於描述不被消息分析所分析的域內容和域值。*TEXT-UTF8包含了UTF-8字符集的字符(RFC2279[7])。TEXT-UTF8-TRIM規則是用於描述一個n t引號引起來的字符串,其前後的空白是無意義的。在這裏,SIP和HTTP不同,HTTP使用的是ISO 8859-1字符集。

TEXT-UTF8-TRIM    = 1*TEXT-UTF8char *(*LWS TEXT-UTF8char)
TEXT-UTF8char    = %x21-7E / UTF8-NONASCII
UTF8-NONASCII    =        %xC0-DF    1UTF8-CONT
/    %xE0-EF 2UTF8-CONT
/    %xF0-F7 3UTF8-CONT
/    %xF8-Fb 4UTF8-CONT
/    %xFC-FD 5UTF8-CONT
UTF8-CONT = %x80-BF

在TEXT-UTF8-TRIM的定義中,CRLF只允許作爲頭域的延長部分存在。當LWS(空格)摺疊的時候,在分析TEXTUTF8-TRIM之前,會使用單個SP代替。

部分協議要素使用了十六進制數字字符。有一些要素(authentication)強制十六進制數字使用小寫字母。

LHEX = DIGIT / %x61-66 ;lowercase a-f

許多SIP頭域值都包含用LWS或者特殊符號分開的詞。除非有額外的說明,這些符號是大小寫不銘感的。當特殊字符作爲參數值存在的時候,這些特殊字符必須通過引號引起來。Call-ID中建立的詞組允許使用絕大部分分隔符。

token        =    1 * ( alphanum / "-" / "." / "!" / "%" / "*"
/ "_" / "+" / "‘" / "’" / "˜" )
separators    =    "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "/" / DQUOTE /
"/" / "[" / "]" / "?" / "=" /
"{" / "}" / SP / HTAB
word        =    1*(alphanum / "-" / "." / "!" / "%" / "*" /
"_" / "+" / "‘" / "’" / "˜" /
"(" / ")" / "<" / ">" /
":" / "/" / DQUOTE /
"/" / "[" / "]" / "?" /
"{" / "}" )
當標誌符號或者分隔符用在要素之間是,空白通常允許在這些字符之前或者之後。

STAR                = SWS "*" SWS ; asterisk
SLASH            = SWS "/" SWS ; slash
EQUAL            = SWS "=" SWS ; equal
LPAREN            = SWS "(" SWS ; left parenthesis
RPAREN            = SWS ")" SWS ; right parenthesis
RAQUOT            = ">" SWS ; right angle quote
LAQUOT            = SWS "<"; left angle quote
COMMA            = SWS "," SWS ; comma
SEMI                = SWS ";" SWS ; semicolon
COLON            = SWS ":" SWS ; colon
LDQUOT            = SWS DQUOTE; open double quotation mark
RDQUOT            = DQUOTE SWS ; close double quotation mark

在SIP頭域中可以使用註釋,通過把註釋放在圓括號中就可以了。只有在頭域的定義中允許”comment”作爲他們的頭域值的一部分纔可以使用註釋。在其他頭域中,圓括號被視同爲頭域值的一部分。

comment    =    LPAREN *(ctext / quoted-pair / comment) RPAREN
ctext        =    %x21-27 / %x2A-5B / %x5D-7E / UTF8-NONASCII
/ LWS

ctext包含了除了左右括號和反斜線之外的所有的字符。在雙引號引起來的字符串中的字串,被視爲單個詞。在引起來的字串中,引號(“)和反斜線需要轉碼。

quoted-string    =    SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
qdtext            =    LWS / %x21 / %x23-5B / %x5D-7E
/ UTF8-NONASCII

反斜線(“/”)可以當作單個字符使用,轉義機制只有在引號引起來的字符串中或者註釋結構中有效。和HTTP/1.1不同的是,CR和LF不能通過這個機制來轉義,這樣可以避免同頭的摺疊的衝突。

quoted-pair        =    "/" (%x00-09 / %x0B-0C
/ %x0E-7F)

SIP-URI            =    "sip:" [ userinfo ] hostport
uri-parameters [ headers ]
SIPS-URI            =    "sips:" [ userinfo ] hostport
uri-parameters [ headers ]
userinfo            =    ( user / telephone-subscriber ) [ ":" password ] "@"
user                =    1*( unreserved / escaped / user-unreserved )
user-unreserved    =    "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
password            =    *( unreserved / escaped /
"&" / "=" / "+" / "$" / "," )
hostport            =    host [ ":" port ]
host                =    hostname / IPv4address / IPv6reference
hostname            =    *( domainlabel "." ) toplabel [ "." ]
domainlabel        =    alphanum
/ alphanum *( alphanum / "-" ) alphanum
toplabel            =    ALPHA / ALPHA *( alphanum / "-" ) alphanum
IPv4address        =    1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
IPv6reference        =    "[" IPv6address "]"
IPv6address        =    hexpart [ ":" IPv4address ]
hexpart            =    hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ]
hexseq            =    hex4 *( ":" hex4)
hex4                =    1*4HEXDIG
port                =    1*DIGIT

對於電話描述(telephone-subscriber)的BNF說明在RFC2806[9]中。注意,無論如何,如果在這裏允許的字符,如果在SIP URI中的user部分不許可,那麼就一定要用轉義。

uri-parameters        =    *( ";" uri-parameter)
uri-parameter        =    transport-param / user-param / method-param
/ ttl-param / maddr-param / lr-param / other-param
transport-param    =    "transport="
( "udp" / "tcp" / "sctp" / "tls"
/ other-transport)
other-transport        =    token
user-param        =    "user=" ( "phone" / "ip" / other-user)
other-user            =    token
method-param        =    "method=" Method
ttl-param            =    "ttl=" ttl
maddr-param        =    "maddr=" host
lr-param            =    "lr"
other-param        =    pname [ "=" pvalue ]
pname            =    1*paramchar
pvalue            =    1*paramchar
paramchar            =    param-unreserved / unreserved / escaped
param-unreserved    =    "[" / "]" / "/" / ":" / "&" / "+" / "$"

headers            =    "?" header *( "&" header )
header            =    hname "=" hvalue
hname            =    1*( hnv-unreserved / unreserved / escaped )
hvalue            =    *( hnv-unreserved / unreserved / escaped )
hnv-unreserved    =    "[" / "]" / "/" / "?" / ":" / "+" / "$"

SIP-message        =    Request / Response
Request            =    Request-Line
*( message-header )
CRLF
[ message-body ]
Request-Line        =    Method SP Request-URI SP SIP-Version CRLF
Request-URI        =    SIP-URI / SIPS-URI / absoluteURI
absoluteURI        =    scheme ":" ( hier-part / opaque-part )
hier-part            =    ( net-path / abs-path ) [ "?" query ]
net-path            =    "//" authority [ abs-path ]
abs-path            =    "/" path-segments
opaque-part        =    uric-no-slash *uric
uric                =    reserved / unreserved / escaped
uric-no-slash        =    unreserved / escaped / ";" / "?" / ":" / "@"
/ "&" / "=" / "+" / "$" / ","
path-segments        =    segment *( "/" segment )
segment            =    *pchar *( ";" param )
param                =    *pchar
pchar                =    unreserved / escaped /
":" / "@" / "&" / "=" / "+" / "$" / ","
scheme            =    ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
authority            =    srvr / reg-name
srvr                =    [ [ userinfo "@" ] hostport ]
reg-name            =    1*( unreserved / escaped / "$" / ","
/ ";" / ":" / "@" / "&" / "=" / "+" )
query                =    *uric
SIP-Version        =    "SIP" "/" 1*DIGIT "." 1*DIGIT

message-header    =    (Accept
/ Accept-Encoding
/ Accept-Language
/ Alert-Info
/ Allow
/ Authentication-Info
/ Authorization
/ Call-ID
/ Call-Info
/ Contact
/ Content-Disposition
/ Content-Encoding
/ Content-Language
/ Content-Length
/ Content-Type
/ CSeq
/ Date
/ Error-Info
/ Expires
/ From
/ In-Reply-To
/ Max-Forwards
/ MIME-Version
/ Min-Expires
/ Organization
/ Priority
/ Proxy-Authenticate
/ Proxy-Authorization
/ Proxy-Require
/ Record-Route
/ Reply-To
/ Require
/ Retry-After
/ Route
/ Server
/ Subject
/ Supported
/ Timestamp
/ To
/ Unsupported
/ User-Agent
/ Via
/ Warning
/ WWW-Authenticate
/ extension-header) CRLF

INVITEm            =    %x49.4E.56.49.54.45 ; INVITE in caps
ACKm                =    %x41.43.4B ; ACK in caps
OPTIONSm        =    %x4F.50.54.49.4F.4E.53 ; OPTIONS in caps
BYEm                =    %x42.59.45 ; BYE in caps
CANCELm            =    %x43.41.4E.43.45.4C ; CANCEL in caps
REGISTERm        =    %x52.45.47.49.53.54.45.52 ; REGISTER in caps
Method            =    INVITEm / ACKm / OPTIONSm / BYEm
/ CANCELm / REGISTERm
/ extension-method
extension-method    =    token
Response            =    Status-Line
*( message-header )
CRLF
[ message-body ]

Status-Line        =    SIP-Version SP Status-Code SP Reason-Phrase CRLF
Status-Code        =    Informational
/ Redirection
/ Success
/ Client-Error
/ Server-Error
/ Global-Failure
/ extension-code
extension-code        =    3DIGIT
Reason-Phrase    =    *(reserved / unreserved / escaped
/ UTF8-NONASCII / UTF8-CONT / SP / HTAB)

Informational        =    "100" ; Trying
/ "180" ; Ringing
/ "181" ; Call Is Being Forwarded
/ "182" ; Queued
/ "183" ; Session Progress

Success            =    "200" ; OK

Redirection        =    "300" ; Multiple Choices
/ "301" ; Moved Permanently
/ "302" ; Moved Temporarily
/ "305" ; Use Proxy
/ "380" ; Alternative Service
Client-Error = "400" ; Bad Request
/ "401" ; Unauthorized
/ "402" ; Payment Required
/ "403" ; Forbidden
/ "404" ; Not Found
/ "405" ; Method Not Allowed
/ "406" ; Not Acceptable
/ "407" ; Proxy Authentication Required
/ "408" ; Request Timeout
/ "410" ; Gone
/ "413" ; Request Entity Too Large
/ "414" ; Request-URI Too Large
/ "415" ; Unsupported Media Type
/ "416" ; Unsupported URI Scheme
/ "420" ; Bad Extension
/ "421" ; Extension Required
/ "423" ; Interval Too Brief
/ "480" ; Temporarily not available
/ "481" ; Call Leg/Transaction Does Not Exist
/ "482" ; Loop Detected
/ "483" ; Too Many Hops
/ "484" ; Address Incomplete
/ "485" ; Ambiguous
/ "486" ; Busy Here
/ "487" ; Request Terminated
/ "488" ; Not Acceptable Here
/ "491" ; Request Pending
/ "493" ; Undecipherable

Server-Error        =    "500" ; Internal Server Error
/ "501" ; Not Implemented
/ "502" ; Bad Gateway
/ "503" ; Service Unavailable
/ "504" ; Server Time-out
/ "505" ; SIP Version not supported
/ "513" ; Message Too Large


Global-Failure        =    "600" ; Busy Everywhere
/ "603" ; Decline
/ "604" ; Does not exist anywhere
/ "606" ; Not Acceptable

Accept            =    "Accept" HCOLON
[ accept-range *(COMMA accept-range) ]
accept-range        =    media-range *(SEMI accept-param)
media-range        =    ( "*/*"
/ ( m-type SLASH "*" )
/ ( m-type SLASH m-subtype )
) *( SEMI m-parameter )
accept-param        =    ("q" EQUAL qvalue) / generic-param
qvalue            =    ( "0" [ "." 0*3DIGIT ] )
/ ( "1" [ "." 0*3("0") ] )
generic-param        =    token [ EQUAL gen-value ]
gen-value            =    token / host / quoted-string

Accept-Encoding    =    "Accept-Encoding" HCOLON
[ encoding *(COMMA encoding) ]
encoding            =    codings *(SEMI accept-param)
codings            =    content-coding / "*"
content-coding        =    token

Accept-Language    =    "Accept-Language" HCOLON
[ language *(COMMA language) ]
language            =    language-range *(SEMI accept-param)
language-range    =    ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) / "*" )

Alert-Info            = "Alert-Info" HCOLON alert-param *(COMMA alert-param)
alert-param        = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )

Allow                =    "Allow" HCOLON [Method *(COMMA Method)]
Authorization        =    "Authorization" HCOLON credentials
credentials            =    ("Digest" LWS digest-response)
/ other-response
digest-response    =    dig-resp *(COMMA dig-resp)
dig-resp            =    username / realm / nonce / digest-uri
/ dresponse / algorithm / cnonce
/ opaque / message-qop
/ nonce-count / auth-param
username            =    "username" EQUAL username-value
username-value    =    quoted-string
digest-uri            =    "uri" EQUAL LDQUOT digest-uri-value RDQUOT
digest-uri-value        =    rquest-uri ; Equal to request-uri as specified
by HTTP/1.1
message-qop        =    "qop" EQUAL qop-value


cnonce            =    "cnonce" EQUAL cnonce-value
cnonce-value        =    nonce-value
nonce-count        =    "nc" EQUAL nc-value
nc-value            =    8LHEX
dresponse            =    "response" EQUAL request-digest
request-digest        =    LDQUOT 32LHEX RDQUOT
auth-param        =    auth-param-name EQUAL
( token / quoted-string )
auth-param-name    =    token
other-response        =    auth-scheme LWS auth-param
*(COMMA auth-param)
auth-scheme        =    token

Authentication-Info    =    "Authentication-Info" HCOLON ainfo
*(COMMA ainfo)
ainfo                =    nextnonce / message-qop
/ response-auth / cnonce
/ nonce-count
nextnonce            =    "nextnonce" EQUAL nonce-value
response-auth        =    "rspauth" EQUAL response-digest
response-digest    =    LDQUOT *LHEX RDQUOT

Call-ID            =    ( "Call-ID" / "i" ) HCOLON callid
callid                =    word [ "@" word ]

Call-Info            =    "Call-Info" HCOLON info *(COMMA info)
info                =    LAQUOT absoluteURI RAQUOT *( SEMI info-param)
info-param            =    ( "purpose" EQUAL ( "icon" / "info"
/ "card" / token ) ) / generic-param
Contact            =    ("Contact" / "m" ) HCOLON
( STAR / (contact-param *(COMMA contact-param)))
contact-param        =    (name-addr / addr-spec) *(SEMI contact-params)
name-addr            =    [ display-name ] LAQUOT addr-spec RAQUOT
addr-spec            =    SIP-URI / SIPS-URI / absoluteURI
display-name        =    *(token LWS)/ quoted-string

contact-params        =    c-p-q / c-p-expires
/ contact-extension
c-p-q                =    "q" EQUAL qvalue
c-p-expires        =    "expires" EQUAL delta-seconds
contact-extension    =    generic-param
delta-seconds        =    1*DIGIT

Content-Disposition    =    "Content-Disposition" HCOLON
disp-type *( SEMI disp-param )
disp-type            =    "render" / "session" / "icon" / "alert"
/ disp-extension-token
disp-param        =    handling-param / generic-param
handling-param    =    "handling" EQUAL
( "optional" / "required"
/ other-handling )
other-handling        =    token
disp-extension-token =    token

Content-Encoding    =    ( "Content-Encoding" / "e" ) HCOLON
content-coding *(COMMA content-coding)

Content-Language    =    "Content-Language" HCOLON
language-tag *(COMMA language-tag)
language-tag        =    primary-tag *( "-" subtag )
primary-tag        =    1*8ALPHA
subtag            =    1*8ALPHA

Content-Length        =    ( "Content-Length" / "l" ) HCOLON 1*DIGIT
Content-Type        =    ( "Content-Type" / "c" ) HCOLON media-type
media-type        =    m-type SLASH m-subtype *(SEMI m-parameter)
m-type            =    discrete-type / composite-type
discrete-type        =    "text" / "image" / "audio" / "video"
/ "application" / extension-token
composite-type        =    "message" / "multipart" / extension-token
extension-token    =    ietf-token / x-token
ietf-token            =    token
x-token            =    "x-" token
m-subtype            =    extension-token / iana-token
iana-token            =    token
m-parameter        =    m-attribute EQUAL m-value
m-attribute            =    token
m-value            =    token / quoted-string

CSeq                =    "CSeq" HCOLON 1*DIGIT LWS Method

Date                =    "Date" HCOLON SIP-date
SIP-date            =    rfc1123-date
rfc1123-date        =    wkday "," SP date1 SP time SP "GMT"
date1                =    2DIGIT SP month SP 4DIGIT
; day month year (e.g., 02 Jun 1982)
time                =    2DIGIT ":" 2DIGIT ":" 2DIGIT
; 00:00:00 - 23:59:59
wkday                =    "Mon" / "Tue" / "Wed"
/ "Thu" / "Fri" / "Sat" / "Sun"
month                =    "Jan" / "Feb" / "Mar" / "Apr"
/ "May" / "Jun" / "Jul" / "Aug"
/ "Sep" / "Oct" / "Nov" / "Dec"

Error-Info            =    "Error-Info" HCOLON error-uri *(COMMA error-uri)

error-uri            = LAQUOT absoluteURI RAQUOT *( SEMI generic-param )

Expires            =    "Expires" HCOLON delta-seconds
From                =    ( "From" / "f" ) HCOLON from-spec
from-spec            =    ( name-addr / addr-spec )
*( SEMI from-param )
from-param        =    tag-param / generic-param
tag-param            =    "tag" EQUAL token

In-Reply-To        =    "In-Reply-To" HCOLON callid *(COMMA callid)

Max-Forwards        =    "Max-Forwards" HCOLON 1*DIGIT

MIME-Version        =    "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT

Min-Expires        =    "Min-Expires" HCOLON delta-seconds

Organization        =    "Organization" HCOLON [TEXT-UTF8-TRIM]

Priority            =    "Priority" HCOLON priority-value
priority-value        =    "emergency" / "urgent" / "normal"
/ "non-urgent" / other-priority
other-priority        =    token

Proxy-Authenticate    =    "Proxy-Authenticate" HCOLON challenge
challenge            =    ("Digest" LWS digest-cln *(COMMA digest-cln))
/ other-challenge
other-challenge        =    auth-scheme LWS auth-param
*(COMMA auth-param)
digest-cln            =    realm / domain / nonce
/ opaque / stale / algorithm
/ qop-options / auth-param
realm                =    "realm" EQUAL realm-value
realm-value        =    quoted-string
domain            =    "domain" EQUAL LDQUOT URI
*( 1*SP URI ) RDQUOT
URI                =    absoluteURI / abs-path
nonce                =    "nonce" EQUAL nonce-value
nonce-value        =    quoted-string
opaque            =    "opaque" EQUAL quoted-string
stale                =    "stale" EQUAL ( "true" / "false" )
algorithm            =    "algorithm" EQUAL ( "MD5" / "MD5-sess"
/ token )
qop-options        =    "qop" EQUAL LDQUOT qop-value
*("," qop-value) RDQUOT
qop-value            =    "auth" / "auth-int" / token

Proxy-Authorization    =    "Proxy-Authorization" HCOLON credentials

Proxy-Require        =    "Proxy-Require" HCOLON option-tag
*(COMMA option-tag)
option-tag            =    token

Record-Route        = "Record-Route" HCOLON rec-route *(COMMA rec-route)
rec-route            =    name-addr *( SEMI rr-param )
rr-param            =    generic-param

Reply-To            =    "Reply-To" HCOLON rplyto-spec
rplyto-spec            =    ( name-addr / addr-spec )
*( SEMI rplyto-param )
rplyto-param        =    generic-param

Require            =    "Require" HCOLON option-tag *(COMMA option-tag)

Retry-After            =    "Retry-After" HCOLON delta-seconds
[ comment ] *( SEMI retry-param )

retry-param        =    ("duration" EQUAL delta-seconds)
/ generic-param

Route                =    "Route" HCOLON route-param *(COMMA route-param)
route-param        =    name-addr *( SEMI rr-param )

Server            =    "Server" HCOLON server-val *(LWS server-val)
server-val            =    product / comment
product            =    token [SLASH product-version]
product-version        =    token

Subject            =    ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM]

Supported            =    ( "Supported" / "k" ) HCOLON
[option-tag *(COMMA option-tag)]

Timestamp            =    "Timestamp" HCOLON 1*(DIGIT)
[ "." *(DIGIT) ] [ LWS delay ]
delay                =    *(DIGIT) [ "." *(DIGIT) ]

To                =    ( "To" / "t" ) HCOLON ( name-addr
/ addr-spec ) *( SEMI to-param )
to-param            =    tag-param / generic-param

Unsupported        = "Unsupported" HCOLON option-tag *(COMMA option-tag)
User-Agent        =    "User-Agent" HCOLON server-val *(LWS server-val)

Via                =    ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
via-parm            =    sent-protocol LWS sent-by *( SEMI via-params )
via-params        =    via-ttl / via-maddr
/ via-received / via-branch
/ via-extension
via-ttl                =    "ttl" EQUAL ttl
via-maddr            =    "maddr" EQUAL host
via-received        =    "received" EQUAL (IPv4address / IPv6address)
via-branch            =    "branch" EQUAL token
via-extension        =    generic-param
sent-protocol        =    protocol-name SLASH protocol-version
SLASH transport
protocol-name        =    "SIP" / token
protocol-version    =    token
transport            =    "UDP" / "TCP" / "TLS" / "SCTP"
/ other-transport
sent-by            =    host [ COLON port ]
ttl                    =    1*3DIGIT ; 0 to 255

Warning            = "Warning" HCOLON warning-value *(COMMA warning-value)
warning-value        =    warn-code SP warn-agent SP warn-text
warn-code            =    3DIGIT
warn-agent        =    hostport / pseudonym
; the name or pseudonym of the server adding
; the Warning header, for use in debugging
warn-text            =    quoted-string
pseudonym        =    token

WWW-Authenticate    =    "WWW-Authenticate" HCOLON challenge

extension-header    =    header-name HCOLON header-value
header-name        =    token
header-value        =    *(TEXT-UTF8char / UTF8-CONT / LWS)
message-body        =    *OCTET

26 安全考慮:威脅模式和安全應用建議。

SIP不是一個容易進行安全保護的協議。它使用的中間媒體,以及它的多面信任關係,它希望的節點之間交互基於互不信任的關係,它的用戶到用戶的操作使得安全保證非常重要。今天,我們需要找到基於廣泛環境和使用方法的很好的安全解決方案。爲了達到這一目標,我們需要建立對SIP的不同使用的幾種安全機制。

注意SIP的安全性本身同SIP使用的傳輸協議比如RTP的安全性或者和SIP包體的實現的安全性本身沒有繼承關係(雖然MIME安全體系是SIP安全體系的一個基石)。任何和一個會話相關的媒介都可以被端到端的加密,並且這個和相關的SIP信令無關。媒體加密是在本文檔討論範疇之外的。

首先對一系列的經典的威脅模式的分析可以在很大程度上描繪了SIP所需要的安全需要。這些威脅模式所針對的地址需要一些安全保護,我們接下來通過對集中安全集中的詳細分析,來講述如何這些安全機制能夠提供對這個地址的安全保護。接着我們就可以定義SIP實現者的需求,並且通過提供一個安全配置樣例來描述應用於提高SIP安全性的這些安全機制。本節也標註了一些隱私相關的註解。

26.1 攻擊和威脅模式
本節講述了對SIP部屬來說常見的威脅模式。這些威脅模式是經過特別篩選的,用來體現各個SIP所需要的安全保衛服務。接下來的例子並不是完整的針對SIP的威脅模式列表;不過他們是”經典”的例子,用來代表各類對SIP的攻擊。

這些攻擊假設攻擊者可以從網絡上讀取任何報文-這是因爲SIP會通常基於公共網絡Internet。在網絡上的攻擊者通常可以更改報文內容(可能基於中間某個節點來更改)。攻擊者可以希望盜取服務,竊聽通訊,或者干擾會話。

26.1.1 註冊服務 Hijacking。
SIP註冊機制是提供一個用戶UA把自己的信息到一個註冊服務器上,在這個信息中,可以用address-of-record找到這個用戶的地址。註冊服務器會檢查在REGISTER消息中的From頭域所提供的身份說明,來決定是否這個請求可以修改由To頭域所包含的address-of-record的相關聯繫地址。這兩個頭域通常是相同的,也會有很多第三方代替用戶註冊聯繫地址的情況。

SIP請求的From頭域,可以被一個UA的擁有者任意修改,這就給惡意註冊信息打開了方便之門。一個成功模擬一個UA,通過檢查來修改一個address-of-record的相關聯繫地址,可以,例如先註銷某個URI的所有聯繫地址,然後把自己的設備地址註冊上去,這樣所有對原來URI的地址的請求將發往攻擊者的設備。

這種攻擊屬於很常見的對沒有請求發前方數字簽名的攻擊。任何有意義的SIP UAS(比如對傳統電話呼叫的SIP 網關等等),也許希望通過對收到的請求做認證來控制對自己資源的訪問。就算是最終終端UA,例如SIP電話,也會有對原始請求身份的驗證要求。這個威脅表明了SIP實體需要對原是請求做安全認證的安全服務需要。

26.1.2 模仿一個服務器
對於請求發送到的區域,一般是用Request-URI來標誌的。UA通常直接聯繫這個區域中的服務器來發送請求。不過總會存在一個可能,就是攻擊者把自己模仿成爲遠端的服務器,這樣UA的請求可能會被其他人中間截獲。

例如,我們考慮這樣一個情況:一個轉發服務器在一個區域:chicago.com,它模擬的轉發服務器在另外一個區域: biloxi.com。用戶UA要發送一個請求到biloxi.com,但是chicago.com的轉發服務器回答了一個僞造的應答,並且有僞造的頭域就好像應答是從biloxi.com回來的一樣。在轉發應答中的僞造的聯繫地址可以引導原始UA到一個不合適的或者不安全的資源,或者簡單的阻止發送請求到biloxi.com。

這個常見的威脅有着許多的成員,並且相當嚴重。作爲和註冊服務hijacking相反的威脅,我們考慮這個情況: 當註冊服務信息發送給biloxi.com的被chicago.com截獲,並且迴應給註冊者一個僞造的301(Moved Permanently)應答。這個應答可能看起來是從biloxi.com來得,並且指明瞭chicago.com作爲新的註冊服務。那麼這個原始UA的所有REGISTER請求就會轉發到chicago.com了。

要想防止這個威脅,那麼就需要UA能夠對接收他們請求的服務器進行身份鑑定。

26.1.3 修改消息包體
當然,SIP UA路由請求通過信任的proxy服務器是一件必然的事情。不管這個信任關係是如何建立的(在本節的其他地方有講proxy的認證),UA可以信任proxy來轉發請求,而不是檢查懷疑請求中的包體被修改了。

考慮UA使用SIP消息體來進行媒體會話的會話密鑰通訊的情況。雖然它信任本域的proxy服務器,但是它也不希望域的管理者能夠解密後續的媒體通訊(就是不希望proxy得到這個會話密鑰)。更糟糕的是,如果這個proxy服務器是有惡意的,他可以修改這個會話密鑰,就像中間人一樣,或者改變原始請求UA的安全特性。

這個類型的威脅不僅僅是對會話密鑰,對所有SIP端到端的內容都有威脅。這可能包含對需要展示給用戶的MIME包體,SDP或者電話信令等內容的威脅。攻擊者可能試圖修改SDP包體,例如,給RTP媒體流增加一個竊聽設備來偷聽語音通話信息。

同樣需要注意的是,有一些SIP頭域是對端到端有一定含義的,比如Subject。UA可以決定保護這些頭域和包體(比如中間惡意的攻擊者可以把Subject頭域更改成爲看起來好像是一個惡意郵件)。不過,因爲很多頭域都是proxy服務器在處理請求轉發的時候需要合法檢查或者更改的,所以不是所有的頭域都需要端到端的保護。

基於這些原因,UA可以加密SIP包體,並且對端到端的頭域做一定的限制。對包體的安全服務要求包含了機密性,完整性和身份認證。這些端到端的安全服務應當與用於和中間節點交互的安全機制無關或者不依賴。

26.1.4 破壞會話
當對話被初始消息所建立,後續的請求可以用於修改對話並且/或者會話的狀態。對於會話的負責者來說,非常重要的事情是確定請求不是由攻擊者僞造的。

我們考慮這樣一個情況,一個第三者攻擊者截獲了一些初始信息,這些初始信息是對話的雙方在建立會話是交換的參數等等(To tag,From tag,等等),並且這個攻擊者在會話中插入了一個BYE請求。攻擊者可以選擇假造一個從會話的任意方的請求。當一個BYE被對方接收到,會話就會被提前終止。

類似會話中的威脅,有僞造re-INVITE修改會話(可能減少會話的安全性,或者作爲竊聽攻擊轉發媒體流)。

對於這種威脅,最有效的對策就是對BYE的發送方做身份認證。在這個例子中,接受方只需要確認BYE是從建立對話的對方發起的就可以了。同樣的,如果攻擊者不能夠知道會話的參數,他也沒有辦法僞造BYE。但是,有些中間節點(比如proxy服務器)需要這些參數來判定是否會話已經建立連接。

26.1.5 拒絕服務和擴展。
DOS(拒絕服務)攻擊主要是使得一個特定網絡節點無法工作,通常是通過轉發超大量的網絡通訊阻塞它的網絡接口。分佈式的拒絕服務攻擊允許一個網絡用戶導致大量的網絡服務器來對一個目標做洪水攻擊。

在很多架構下,SIP proxy服務器是基於公網的,因爲它需要處理全球的IP終端的請求。這樣SIP就給這些分佈式拒絕服務攻擊者提供了很多機會,這樣就必須要求SIP系統的設計者和管理者能夠識別這樣的攻擊並且定位這樣的攻擊者。

攻擊者可以發出包含假IP地址及其相關的Via頭域的請求,這個Via頭域標誌了被攻擊的主機地址,就像這個請求是從這個主機地址來的一樣。然後把這個請求發給大量的SIP節點,這樣不幸的SIP UA或者proxy就會給被攻擊的主機產生大量的垃圾應答,從而形成拒絕服務攻擊。

類似的,攻擊者可以用在請求中僞造的Route頭域值來標誌被攻擊的目的主機,並且把這個消息發送到分支proxy,這些分支proxy會放大請求數量發送給目標主機。

Record-Route頭域也可以產生類似的效果。當一個攻擊者確定一個被請求初始化的SIP對話會向回產生很多事務的時候,那麼Record-Route頭域也可以被用於攻擊。

如果REGISTER請求沒有經過註冊服務器進行適當的認證,那麼就會有很多拒絕服務的攻擊的機會。攻擊者可以在一個域中,首先把一些或者全部的用戶都註銷,從而防止這些用戶被加入新的會話。接着一個攻擊者可以在註冊服務器上註冊大量的聯繫地址,這些聯繫地址都指向同一個被攻擊的服務器,這樣可以使得這個註冊服務器和其他相關的proxy服務器對分佈式DOS攻擊進行放大。攻擊者也會嘗試通過註冊大量的垃圾來耗盡註冊服務器可能的內存或者硬盤。

多點傳送的SIP請求可以非常明顯的增大拒絕服務攻擊的可能性。
 
這些展示的問題需要定義一個架構來把拒絕服務攻擊造成的影響最小化,並且需要在安全機制中對這類攻擊特別留意。

26.2 安全機制
從上邊講述的威脅來看,我們得到了SIP協議所需要的基本安全服務,他們是:保護消息的隱私性和完整性,保護重現(replay)攻擊或者消息欺騙,提供會話參與者的身份認證和隱私保護,保護拒絕服務攻擊。SIP消息中的包體分別要求機密性,完整性和身份認證。

比爲SIP重新定義新的安全機制更好的是,SIP可以重用已經存在的HTTP或者SMTP的安全機制。

全加密的消息提供了最好的機密保護-它也可以保證消息不被噁心的中間節點更改。不過SIP請求和應答不能簡單的進行端到端的加密,因爲在大多數網絡架構下,消息的頭域比如Request-URI,Route,Via在中間經過的proxy中需要可見,這樣SIP請求才能被正確路由。注意,proxy服務器需要修改一些消息的特定屬性(比如增加Via頭域),這樣才能保證SIP正常工作。那麼proxy服務器就必須被UA信任,至少在某種程度上信任。爲了這個目標,我們建議爲SIP提供低層次的安全機制,他們是基於節點到節點的整個SIP請求和應答的在線加密,並且語序終端節點校驗他們發出請求的proxy服務器的身份。

SIP實體也可以爲安全保證,需要驗證對方的身份。當SIP終端向對方UA或者proxy服務器,聲明它的用戶的身份時,這個身份應當是可以通過某種方法驗證的。SIP中的數字簽名機制就是爲了這個需要的。

SIP消息體的一個獨立的安全(加密)機制提供了另一個端到端的相互認證方式,也降低了UA必須信任中間節點的程度。

26.2.1 通訊和網絡層的安全
通訊或者網絡層的安全機制是加密信號通訊,保證消息機密的和完整的傳送。

很多情況下,低層次的安全是通過證書實現的,這些證書可以在很多架構下用於提供身份認證使用。

兩個通常使用的方法,提供了通訊層和網絡層的安全,他們是TLS[25]和IPSec[26]。

IPSec是一組網絡層的協議工具,他們可以一起使用來作爲傳統IP通訊的安全替代。IPSec最常用於一組主機或者管理的域有一個現存的互相信任關係的架構下。Ipsec通常由主機的操作系統級別實現,或者在一個提供機密通訊和完整性保證的通訊安全網關上實現(比如VPN結構),IPSec也可以用於點到點的結構。

在很多結構下,IPSec並不要求和SIP應用一起使用;IPSec可能是最適合於部屬在那種難於直接在SIP服務器上增加安全性的情況。具有預先共享密鑰關係的UA和他們的第一個節點的proxy服務器很適合使用IPSec。爲SIP部屬的IPSec要求一個IPSec 描述了協議工具的profile。這個profile在本文檔中沒有提供。

TLS提供了通訊層的安全性,基於連接相關的協議(TCP)。可以通過在Via頭域或者在一個SIP URI中列明”tls” (表示基於TCP的TLS)指定通訊協議爲TLS。TLS最適合沒有事先定義的信任關係的點到點的結構。例如Alice 信任她的本地proxy服務器,這個服務器在進行證書交換後信任Bob的本地proxy服務器,這個Bob的本地proxy服務器是Bob信任的,因此Bob可以和Alice安全的通訊。

TLS必須和SIP應用緊緊聯繫在一起。注意在SIP中的通訊機制是點到點的,因此一個基於TLS發送請求到proxy服務器的UA並不能保證這個TLS會在端到端的應用。

當實現者在SIP應用中使用TLS的時候,實現者必須支持最小集合的TLS_RSA_WITH_AES_128_CBC_SHA密碼套件[6]。並且爲了向後兼容,proxy服務器,重定向服務器和註冊服務器應當支持TLS_RSA_WITH3DES_EDE_CBC_SHA。實現者也可以支持其他密碼套件。

26.2.2 SIPS URI方案
SIPS URI方案是SIP URI(19節)語法的一個附加,雖然這個方案串是”sips”不同於”sip”。SIPS的語義和SIP URI的語義十分不同。SIPS 允許指定希望通過安全訪問的資源。SIPS URI可以當作一個特定用戶的address-of-record使用-這個用戶是已知的(根據他們的名片,在他盟請求的From頭域,在REGISTER請求的To頭域)。當在請求中使用Request-URI,SIPS 方案指出請求經過的每一個節點,知道請求到達目的這個Request-URI指明的SIP元素,必須通過TLS進行加密;當請求抵達目標的域,他會根據目標域的本地安全策略和轉發策略,很有可能最後一部也是用TLS到達UAS。當用在請求的發起方(就像這種情況,當他們使用SIPS URI當作目標的address-of-record一樣),SIPS只是這個實體請求,到目的主機的所有路徑都應當加密。

SIPS方案適用於很多在SIP中應用的SIP URI,比如附加域Request-Uri,包含在address-of-record,聯繫地址(Contact的內容,包含REGISTER方法的頭域等等),還有Route頭域等等。在每個用法中,SIPS URI方案允許這些存在的URI來指明需要安全訪問的資源。這些由SIPS URI所替換的東西,有他們自己的安全屬性([4]中詳細介紹)。

對SIPS的使用在細節上要求必須具備TLS互相的認證,並且要求支持密碼套件TLS_RSA_WITH_AES_128_CBC_SHA。在認證過程中接收到的信任書應當從客戶端持有的信任書跟節點開始驗證;對信任書驗證失敗應當導致請求的失敗。

注意在SIPS URI方案中,通訊層是和TLS沒有依賴關係的,並且因此”sips:[email protected];transport=tcp”和”sips:[email protected];transport=sctp”都是合法的(雖然注意到UDP不能用於SIPS的傳送)。我們不建議使用類似”transport=tls”的方式,部分原因是因爲這是用於請求的單個節點之間的通訊。這是從RFC2543的一個變化。

將address-of-record用SIPS URI發出的用戶,如果在非可靠通訊協議上收到的請求,可以操作設備來拒絕這個請求。

26.2.3 HTTP Authentication
SIP提供了認證機制,基於HTTP認證的身份認證機制,他們依賴於401倒407應答碼和相關頭域來提供拒絕不信任的信任書。對於SIP使用的HTTP Digest認證機制,並沒有做重大的修改,它提供了replay攻擊的保護和單向認證關係。

對SIP的Digest 認證使用在22節有描述。

26.2.4 S/MIME
就像上邊講述的,在端到端的過程中加密整個SIP消息體,可以提供機密性的保護,但是並非所有的字段都能使用這個機制進行保護,因爲中間的網絡節點(比如proxy服務器),需要根據讀取適當的頭域然後決定這個消息應當轉發倒哪裏,並且如果這些中間節點由於安全原因被排出在外,那麼SIP消息從本質上就是不能路由的。

不過,S/MIME允許SIP 的UA在SIP中加密MIME包體,在不影響消息頭的情況下,在端到端的通訊中加密這些MIME包體。S/MIME可以提供消息體的端到端的完整性和機密性,同樣也提供了雙向的認證機制。使用S/MIME也可以通過SIP消息隧道,爲SIP頭域提供一個完整性和機密性的方案。

對SIP的S/MIME使用在23節講述。

26.3 安全機制的實現
26.3.1 對SIP實現者的要求
proxy服務器,重定向服務器,和註冊服務器必須實現TLS,並且必須支持雙向的和單向的認證關係。強烈建議UA可以初始化TLS;UA同樣可以作爲一個TLS服務器。proxy服務器,重定向服務器和註冊服務器應當有一個站點信任書,這個信任書的主題和他們的規範主機名相關。對於TLS的雙向認證,UA可以有他們自己的信任書,但是本文檔中,沒有規定他們的具體用法。所有的支持TLS的SIP元素必須具備在TLS協商中,驗證信任書的機制;這個使得證書機關(可能是有名的類似web瀏覽器證書發行機構的發行機構)發佈的一個或者多個根信任書成爲必須。所有支持TLS的SIP元素必須同樣支持SIPS URI方案。

Proxy服務器,重定向服務器,註冊服務器,和UA可以實現IPSec或者其他底層的安全協議。

當UA試圖聯繫一個proxy服務器,重定向服務器或者主阿服務器,UAC應當初始化一個TLS連接,在這個連接上發起SIP消息。在某些結構嚇,UAS可以同樣在這些TLS接收請求

Proxy服務器,重定向服務器,註冊服務器,和UA必須實現Digest身份認證,包括所有的22節要求的要點。Proxy服務器,重定向服務器,註冊服務器應當配置成爲至少有一個Digest realm,並且對於給定服務器來說,必須支持至少有一個”realm”字符串和這個服務器的主機名或者hostname相關聯。

UA可以支持MIME包體的加密,並且通過23節描述的那樣使用S/MIME傳送信任書。如果UA具有一個或者多個根身份認證的信任書,用來鑑定TLS或者IPSec的信任書,它應當適當的可以用這些來鑑定S/MIME的信任書。UA可以爲S/MIME身份認證而具有特定的根信任書。

注意,隨着S/MIME實現,將來會有安全擴展,來提高S/MIME的強度。

26.3.2 安全解決方案
這些安全機制的操作,可以在某種程度上和現存的WEB和EMAIL安全模式一致。在高一點的級別來看,UA通過Digest 用戶名和口令把他們自己的身份向服務器(proxy服務器,重定向服務器,註冊服務器)認證;服務器把他們自己向UA單節點認證,或者向另外一個服務器進行單節點(one hop)認證(反之亦然),並且是通過TLS來傳送服務器節點信任書。

在點對點的級別,UA一般信任網絡來進行對方身份的鑑別;不過,如果網絡不能夠鑑定對方身份,或者網絡本身不被信任的情況下,也可以使用S/MIME來提供直接的身份認證。

接下來是一個例子,在這個例子中,不同的UA和服務器使用這些安全機制防止26.1節描述的攻擊威脅。實現者和網絡管理員可以遵循本節末尾給出的指示來防止攻擊威脅,這些指示是作爲實現例子提供的。


26.3.2.1 註冊
當UA上線,並且註冊到它自己的域上,它應當和它的註冊服務器建立一個TLS連接(10節描述了UA怎樣找到它的註冊服務器)。註冊服務器應當提供一個信任書給UA,並且這個信任書的節點必須是這個UA想要註冊的域相關的信任書節點;例如,如果UA向註冊[email protected]這個address-of-record,這個信任書節點必須是一個atlanta.com域的主機(比如sip.atlanta.com)。如果它收到了TLS信任書消息,UA應當校驗這個信任書,並且檢查這個信任書的節點。如果信任書是非法的,作廢的,或者它和持有者不符,UA必須不能發送REGISTER消息和進行註冊處理。

當UA收到註冊服務器提供的一個有效的信任書,UA知道註冊服務器並非一個攻擊者(可能重定向、竊取口令、或者試圖做類似攻擊的攻擊者)。

於是UA創建了一個REGISTER請求,並且Request-URI應當指向從註冊服務器所接收到的信任書站點。當UA通過剛纔建立的TLS連接發送REGISTER請求,註冊服務器應當給出一個401(Proxy Authentication Required)應答。在這個應答中,Proxy-Authenticate頭域的”realm”參數,應當和前邊給出的信任書節點的域相同。當UAC收到這個拒絕,它應當提示給用戶要求信任書,或者根據應答中的”realm”參數,從現有的密鑰組中查找對應的信任書。這個信任書的用戶名應當和REGISTER請求的To頭域的URI的”userinfo”部分相關。當在一個合適的Proxy-Authorization頭域中插入和這個信任書,REGISTER應當重新發送到註冊服務器。

由於註冊服務器要求UA認證它自己,對於攻擊者來說,僞造一個用戶的address-of-record的REGISTER請求是很困難的。同樣注意到由於REGISTER是通過機密的TLS連接發送的,攻擊者不能通過截取REGISTER來記錄信任書來進行重放攻擊。

當註冊請求被註冊服務器接收,UA應當繼續保持TLS連接,這樣使得註冊服務器可以既當作proxy服務器,這個proxy服務器可以作爲管理這個域的proxy服務器。剛完成註冊的TLS連接會繼續保留用於接收UA後續發起的請求。

由於UA已經通過在TLS連接的對方的服務器的認證,所有在這個連接上的請求都是經過proxy 服務器的(由於保留了TLS連接,也就是說,剛纔的註冊服務器更換了角色,變成一個proxy服務器)--攻擊者不能僞造好像是剛纔從這個proxy服務器發送的請求。

26.3.2.2 在域之間的請求
現在我們說,Alice的UA希望和遠端管理的域的一個用戶,這個用戶叫做”[email protected]”,初始化一個會話。我們講會說本地管理的域(atlanta.com)有一個本地外發proxy。

對於一個管理域的Proxy服務器處理那發請求,可以同樣作爲本地的外發proxy;基於簡單的原則,我們假定這就是atlanta.com(否則這時候UA將要初始化一個新的TLS連接到一個獨立的服務器)。假定這時候,這個客戶端已經完成了註冊(參見前邊的步驟),當它發出INVITE請求邀請另外一個用戶的時候,它將重用這個TLS連接到本地proxy服務器(剛纔的註冊服務器)。這個UA在INVITE請求中,將會重用剛纔cache的信任書,這樣可以避免不必要的要求用戶輸入信任書。

當本地的發外服務器驗證了這個UA在INVITE請求中的信任書,它應當檢查Request-URI來決定這個消息應當如何路由(參見[4])。如果這個Request-URI的”domainname”部分和一個本地域相關聯(atlanta.com)而不是和biloxi.com相關,那麼proxy服務器會向本地服務查詢來決定怎樣最好的訪問到被呼叫的用戶。

[email protected]”正在嘗試聯繫呼叫”[email protected]”,本地proxy將會轉發這個請求到Alex和它的註冊服務器所建立的TLS連接上。由於Alex將會通過它的已經通過認證的連接上收到這個請求,它就確定這個Alice的請求是通過了本地管理域的proxy的身份驗證的。

不過,在這個例子中,Request-URI指向的是一個遠程域。在atlanta.com的本地外發服務器應當因此而建立一個和在biloxi.com的遠程proxy服務器的TLS連接。由於這個TLS連接的兩端都是服務器,並且都有服務器的信任書,那麼應當使用雙向的TLS身份認證。連接的雙方應當驗證和檢查對方的信任書,把在信任書中的域名同SIP消息中的頭域做比較。例如,atlanta.com 這個proxy服務器,在這步,應當檢查從對方接收到的關於biloxi.com域的信任書。當檢查完畢,並且TLS協商完成,就建立了基於兩個proxy的安全通道,atlanta.com proxy於是可以把INVITE請求轉發給biloxi.com了。

在biloxi.com的proxy服務器應當檢查atlanta.com的信任書,並且比較信任書提供的域名和INVITE請求的From頭域的”domainname”部分。這個biloxi proxy可以執行嚴格的安全機制,拒絕那些他們被轉發的域和本proxy所管理的域不匹配的請求(這個不太明白)。

這些安全機制可以用來防止SIP和SMTP ‘open relays’一樣經常被用於產生垃圾郵件一樣的信息。

這個政策,只是保證了請求聲明的來源確實是它自己;他並不允許biloxi.com確知如何atlanta.com認證的Alice。只有當biloxi.com由其他方法知道atlanta.com的身份認證機制,他纔可能確知Alice如何證明她的身份的。biloxi.com可以接着使用更嚴格的方法,禁止來自未確定和biloxi.com相同的認證策略的域的請求(就是說所有biloxi.com接受的請求,都必須來自biloxi.com所知道身份認證方式的域)。

當INVITE請求被biloxi.com覈准,proxy服務器應當鑑別現存的TLS通道,如果存在現存的TLS通道,並且是和這個請求中的被叫用戶(在這個例子中是[email protected])相關聯的。那麼這個INVITE請求應當通過這個TLS通道發送給Bob。由於通過這個TLS連接收到的請求,這個TLS連接是剛纔已經在biloxi proxy上通過了身份認證,Bob於是知道From頭域沒有被篡改,並且atlanta.com已經認證了Alice,所以就沒有必要猶豫是否信任Alice的身份。

在他們轉發請求錢,兩個proxy服務器應當在請求中增加Record-Route頭域,這樣所有在這個對話中的後續的請求講過通過這兩個proxy服務器。proxy服務器因此可以在對話生存週期中,繼續提供安全服務。如果proxy服務器並不在Record-Route頭域增加他們自己,以後的消息將會直接端到端的在Alice和Bob中發送,而沒有任何安全措施(除非兩個端點使用了某種獨立的端到端的安全措施,比如S/MIME)。在這個考慮上,SIP梯形模式可以提供一個精美的結構來在proxy服務器節點之間進行磋商,以提供一個Alice和Bob之間的有道理的安全通道。

例如,一個攻擊這個結構的攻擊者將會不能僞造BYE請求並且把他插入Bob和Alice的信令流,因爲攻擊者無從探聽會話的參數,這也是由於通訊的完整性機制保證了Alice和Bob之間的通訊是機密的完整的。

26.3.2.3 點對點請求
另外,考慮這樣一個情況,UA聲稱[email protected]沒有一個本地外發proxy。當Carol希望發送INVITE到[email protected],她的UA應當直接初始化一個TLS連接到biloxi proxy(使用附件[4]中描述的機制來檢查怎樣到達指定的Request-URI)。當她的UA收到一個biloxi proxy發送的信任書,她應當在通過TLS連接發送她的INVITE請求前,正常校驗這個信任書。不過,Carol並沒有義務相biloxi proxy提供她自己的身份,但是她在INVITE請求的”message/sip”包體中,有一個CMS-detached(分離的)簽名。如果Carol在biloxi.com realm有其他信任書的話,就不一定提供這個簽名,但是她在biloxi.com上沒有正式關係,所以她沒有信任書,也就必須提供這個簽名。biloxi proxy可以有嚴格的機制直接把這個請求踢掉,甚至不用麻煩被叫方來驗證這個請求,因爲在From頭域的”domainname”部分,並沒有biloxi.com-它可以被當作這個用戶是未認證的。

biloxi proxy對於Bob用戶有一個政策,就是所有未認證的請求都應當轉發到一個適當的地址,對於[email protected],就是<sipo:[email protected]>。Carol在和biloxi proxy建立的TLS連接上,收到這個轉發請求的應答,於是它信任這個轉發地址的真實性。

Carol應當和目標地址建立一個TCP連接,並且發送一個新的INVITE請求,在這個請求中,Request-URI包含剛纔接收到的聯繫地址(需要重新計算包體中的簽名,因爲請求重新構造了)。Bob從不安全的界面上接收到這個INVITE請求,但是這個UA是特意預留一個不安全的界面,在這個情況下,認可請求中的From頭域並且隨後把INVITE包體中的簽名和一個本地cache的信任書進行匹配。Bob用類似的方法應答,把他自己相Carol進行認證,這樣一個安全的對話就開始了。

某些情況下,在一個域的NAT或者防火牆會阻止UA之間直接建立TCP連接。在這個情況下,如果本地策略許可,proxy服務器可以隱含的做UA之間的請求轉發,並且這個轉發是基於沒有信任關係的(比如不用現存的TLS連接,而是通過TCP明碼的請求轉發)


26.3.2.4 DoS 防護
基於這些安全解決方案,爲了使得拒絕服務(DoS)攻擊造成的影響最小,實現者應當注意如下的指引:

當SIP proxy服務器所在的主機是基於公共internte做路由的,他應當部署在一個具有防護操作策略的管理域中(比如block源路由,過濾ping包等等)。TLS和IPSec都可以在管理域的邊界的防護主機,一起參與安全系統的構家,來提高安全性。這些防護主機可以防護拒絕服務攻擊,確保在管理域中的SIP主機不會被大量的消息阻塞。

不管使用什麼樣的安全措施,對proxy服務器的洪水消息攻擊可以耗盡proxy服務器的資源,並且阻止發送到目的地的正確的請求。對於proxy服務器來說,每一個SIP事務都會好用一定的資源,對於有狀態的服務器來說這個消耗會更大。因此,有狀態的proxy比無狀態的proxy更容易受到洪水攻擊的影響。

UA和proxy服務器應當用一個401(Unauthorized)或者407(Proxy Authentication Required)拒絕有問題的請求,並且對這些有問題的請求不使用正常的應答重發機制,並且對這些未認證的請求把自己當作無狀態的服務器使用。如果攻擊者使用假的頭域值(例如Via)指向一個第三方的被攻擊的服務器,那麼對於401(Unauthorized)或者407(Proxy Authentication Required)應答的重發可能正中攻擊者的下懷。

總得來說,基於TLS簽名的proxy服務器之間的雙向認證機制,降低了中間節點潛在的風險,並且減少了可以用作拒絕服務攻擊的僞造的請求或者應答。這也同樣提高了攻擊者利用無知的SIP節點進行放大攻擊的難度。


26.4 限制
雖然有這些安全機制,在正確應用的時候,可以阻止很多攻擊,但是對於網絡管理者和開發者來說,也必須明白他們也會有很多限制的地方。

26.4.1 HTTP Digest
在SIP中對於HTTP Digest一個限制是Digest的完整性機制在SIP下運作的不是很完美。尤其是,他們提供了對消息中的Request-URI和方法的保護,但是並沒有對UA希望提供加密的所有頭域進行了保護。


RFC2617所提供的回放攻擊保護對於SIP來說也有一些限制。例如,next-nonce機制,並不支持通過管道傳送的請求。防止回放攻擊應當使用nonce-count機制。

另一個HTTP Digest限制是realm的範圍。當用戶希望把他們自己的身份向一個資源(這個資源和他們有着預先存在的關係)進行認證的時候,Digest是有用的,它就像一個服務提供者,用戶是一個客戶端(這是十分常見的場景,因此Digest提供了一個十分有用的功能)。與之對應的,TLS的範圍是基於域之間的,或者multirealm的,因爲信任書通常是全局可驗證的,所以UA可以在不需要預先存在關係的服務器上進行身份驗證。

26.4.2 S/MIME
對於S/MIME的一個最大的限制是對終端用戶來說,缺少廣泛的公共密鑰機構。如果使用的是自簽名(selfsigned)信任書(或者信任書不能被對話的對方所驗證),23.2節描述的基於SIP的密鑰交換機制就容易遭受中間人攻擊(man-in-the-middle),在這個中間人攻擊中,攻擊者可以悄悄檢查和修改S/MIME包體。攻擊者需要截取對話中,雙方的第一個密鑰交換,在請求和應答中移去現有的CMS-detached簽名,並且插入另外的包含攻擊者提供的信任書(但是看起來像是正確地address-of-record的信任書)的CMS-detached 簽名。通訊的雙方都回以爲他們和對方交換了密鑰,實際上他們互相有的只是攻擊者的公鑰。

必須明確注意到攻擊者只能攻擊雙方的第一次的密鑰交換-在後續的情況,密鑰的變更對於UA來說就是不可見的了。同樣使得攻擊者難以竊聽對話雙方的以後的對話中(比如一天內的對話,周內的,或者一年的對話)。

SSH在第一次密鑰交換的時候,也同樣容易受到這個中間人攻擊;但是,雖然衆所周知SSH不完美,但是它確實提高了連接的安全性。對於SIP來說,使用密鑰的指紋可以有些幫助,就像在SSH中一樣。例如,如果SIP的雙方建立了一個語音通訊會話,每一個都可以讀取對方傳送的密鑰指紋,並且可以根據這個指紋和原始指紋做比較。這使得中間人更加難以在語音中模擬通話雙方的密鑰指紋(實際上這個在Clipper 基於芯片的保密電話中使用)。

在S/MIME機制下,如果UA在他們的密鑰組中持有對方address-of-record的信任書,允許UA不用導言來發送加密的請求。不過,存在這個樣的情況,如果某個設備註冊了這個address-of-record,並且沒有持有持有設備當前用戶先前使用的信任書。並且它將因此不能正常處理加密的請求,於是可能會導致某些原本可以避免的錯誤信號。這很像加密的請求被分支的情況。

S/MIME相關的密鑰通常用於和特定用戶(一個address-of-record)關聯起來使用,而不是和一個設備(UA)一起使用。當用戶在設備之間移動,很難把私鑰安全的在UA之間傳遞;一個設備如何獲得這些密鑰不在本文討論。

另外,使用S/MIME更常見的困難是,它可以導致很大的消息,特別是當採用23.4節的SIP隧道戒指的時候。基於這個原因,當使用S/MIME隧道機制的時候,一定要使用TCP通訊協議。

26.4.3 TLS
TLS最大的問題是,它不能基於UDP;TLS要求面向連接的底層通訊協議,對於本文來說,就是TCP。

對於TLS來說,在本地外發proxy服務器和/或者主車服務器上和大量UA,維持很多併發TLS長連接,是一件費力的事情。這導致某些容量問題,特別是在使用加強密鑰套件的時候更容易出現容量問題。維持冗餘的TLS長連接,特別是當UA獨立負責他們的連接,會很耗資源。

TLS只允許SIP實體到他們臨近的認證服務器的連接;TLS提供了嚴格的節點到節點的安全性(hop-by-hop)。無論TLS,還是其他本文檔規定的安全機制,當不能直接建立TCP連接的情況下,都允許客戶通過驗證自己到proxy服務器來到達目的地。

26.4.4 SIPS URI
實際上在請求經過的每一段都使用TLS,要求了最終的UAS必須能夠通過TLS到達(也許是通過SIPS URI作爲一個聯繫地址註冊的)。通常這個目的地是用SIPS描述的。在很多結構下,使用TLS保護一部分請求路徑,最後一部確實依賴於其他的安全機制到UAS。因此SIPS不能保證TLS是真正的端到端的使用。注意,這是由於許多UA不接受進來的TLS連接,甚至那些支持TLS的UA也可能要求要維持一個永久的TLS連接(就像前邊的TLS限制節講述的一樣),目的是爲了作爲UAS從TLS上接收請求。

位置服務,對於SIPS Request-URI來說,是不要求提供SIPS綁定的。雖然位置服務通常由用戶註冊(10.2.1節描述)組成,但是對於一個address-of-record來說,可以由不同的協議和界面都可以提供聯繫地址,並且這些工具都可以用來映射SIPS URI到適當的SIP URI。當對綁定信息查詢的時候,位置服務返回它的聯繫地址,而不關心這個是否是從一個SIPS的Request-URI上收到的請求。如果是轉發服務器訪問位置服務,那就是說取決於處理轉發的Contact頭域的SIP實體來決定聯繫地址的屬性。

如果要求請求經過的全部路徑都使用TLS通訊,那麼對目的域來說稍稍有點麻煩。如果實現困難,也允許在請求傳送節點中的基於密碼認證的proxy服務器,不兼容或者選擇一個折中方案來略過SIPS的轉發機制(在16.6節定義的通常轉發規則)。但是,惡意的中間節點就有可能把一個基於SIPS URI的請求,重新降級成爲SIP URI。

另外,中間節點也可以正常的把一個基於SIP的請求更改成基於SIPS URI的請求。請求的接受方發現請求的Request-URI是基於SIPS URI方案的並不能假設原始請求的Request-URI也是基於SIPS通過中間節點傳送的(從客戶端往後)。

爲了解決這個問題,我們建議請求的收件人,在請求的Request-URI包含一個SIP或者SIPS URI的情況下,檢查To頭域值,看看是否包含一個SIPS URI(雖然注意到Request-URI可以和To頭域URI有相同的URI方案,但是他們不相等並不意味者是一個安全隱患)。雖然客戶端可以在一個請求中把Request-URI和To頭域做成不一樣的,但是當兩個字段的SIPS不一樣的話,那就是可能的安全隱患,並且請求因此應當被接受方拒絕。接受方也可以檢查Via頭域鏈來雙重檢查是否TLS在整個請求路徑中被使用,一直到最近的本地管理域。源UAC也可以用S/MIME來幫助確保原始格式的To頭域被端到端的發送。

如果UAS有原因來相信Request-URI的URI方案在通訊中被非法修改,UA應當提示用戶這個潛在的安全隱患。

作爲更深遠的考量,爲了防止底層的攻擊,如果SIP實體只接受SIPS請求,那麼可以拒絕在非安全端口的連接。

終端用戶應當完全清楚SIPS和SIP URI的區別,他們可以在應答中手工更改這個URI方案。這可以增加或者降低安全性。例如,如果一個攻擊者攻陷了一個DNS的cache,插入了一個假的記錄集,這個記錄集有效刪去了一個proxy服務器的所有SIPS記錄,接着經過這個proxy服務器的SIPS請求就會失效。這時候,一個用戶,看見這個SIPS address-of-record總是失敗,他可以手工改掉URI從SIPS改成SIP,並且重試。當然,這也有一些安全機制防止這類事情發生(如果目標UA真是有神經病拒絕所有非SIPS請求的話)。但是這個限制毫無價值。往好了想,用戶也可以把SIP URI變成SIPS URI。

26.5 Privacy(隱私)
SIP消息經常包含發送者的敏感信息-不只是他們將說些什麼,也包括了他們和誰在通訊,以及他們通訊了多久,以及從那裏到哪裏的通訊等等。很多應用和他們的用戶都要求這類隱私信息對於沒有必要知道的方面來說都必須保持隱祕。

注意,也有隱私信息也有少數直接泄漏的方式。如果用戶或者服務,位於一個容易猜到的地址,比如通過用戶的名字或者機構的聯繫(這是構成Address-of-record的最經常的情形),傳統保證隱私性的方式是通過一個未列出的”電話號碼錶”來實現的。在呼叫方發起的會話邀請中,用戶位置服務可以提供精確的被叫方的位置從而破壞了隱私;在實現上因此應當更嚴格,基於每用戶的原則,根據不同的呼叫方給出不同的位置信息和可用性的信息。這是一個SIP需要解決的完整的問題。

在某些情況下,用戶可能希望在通過身份驗證時,在頭域中隱藏個人信息。這可以應用於不僅是From和相關表現請求發起方信息的頭域,也應用於To頭域-他可能不能由快速撥號的nick-name轉換成爲最終的目的地信息,或者一個爲擴展的一組目標的標誌,當請求被路由的時候,每一個都可以從Request-URI上被移去,但是如果和To頭域初始值相等的時候,不能更改To頭域。因此,他可能由於隱私的原因創建和Request-URI不同的To頭域。

27 IANA 認證
SIP應用中的所有的方法名字,頭域名字,狀態碼,和option tags,都是通過RFC中關於IANA認證節的說明在IANA註冊的。

本規範指示IANA創建了4個新的子註冊項目在:http://www.iana.org/assignments/sip-parameters: Option Tags,Warning Codes(warn-codes),Methods和Response Codes,頭域的子項也在那裏。

27.1 Option Tags
這個規範在http://www.iana.org/assignments/sip-parameters建立了Option Tags註冊項.

Option tags用於類似Require,Supported,Proxy-Require,Unsupoprted這類的頭域,用來支持SIP的擴展兼容性機制(19.2節)。Option tag自身時一個字符串,和特定的SIP選項相關(也就是和特定的SIP擴展相關)。它爲SIP終端確定這個選項。Option tags當被標準的RFC軌跡擴展,它就在IANA註冊了。RFC的IANA認證節必須包含如下內容,這些內容與RFC出版號碼一起在IANA註冊表登記。

o option tag的名字。名字可以是任意長度的,但是應當不要超過20個字母。丙子必須是alphanum(25節)字符。

o 描述擴展的描述信息


27.2 Warn-Codes
本規範在http://www.iana.org/assignments/sip-parameters建立了Warn-Codes註冊項。並且初始發佈的warn-codes值在20.43節列出。附加的warn-codes通過RFC出版物註冊發表。

對於warn-codes表的描述信息如下:

當一個會話描述協議(SDP)(RFC 2327[1])出現問題導致事務失敗的時候,Warning codes在SIP應答信息中提供了對狀態碼的補充信息。
“warn-code”包含了3位數字。第一個數字”3”表示warning是SIP的警告信息。除非以後另有描述,只有3xx警告信息可以被註冊。

300到329的警告信息爲會話描述保留字錯誤保留,330到339爲會話要求基本網絡服務錯誤保留,370到379是爲會話描述要求的QoS參數數量錯誤保留,390到399是無法歸類的雜項警告信息。

27.3 頭域名
本規範在http://www.iana.org/assignments/sip-parameters建立了頭域的註冊項。

爲了註冊一個新的頭域名,下列信息需要在RFC出版物中提供,

o 頭域註冊的RFC號碼
o 註冊的頭域名
o 如果有縮寫,頭域的縮寫版本。

部分常用的頭域可以縮寫成1個字母的簡寫形式(7.3.3節)。簡寫形式只能在SIP工作組複查的時候被登記在RFC出版物上。

27.4 方法和應答碼
本規範在http://www.iana.org/assignments/sip-parameters建立了Method和Response-code的註冊項。並且下邊列出了他們的初始值。初始的方法表如下:

INVITE            [RFC3261]
ACK            [RFC3261]
BYE            [RFC3261]
CANCEL        [RFC3261]
REGISTER        [RFC3261]
OPTIONS        [RFC3261]
INFO            [RFC2976]

應答碼的初始值在21節列出,分爲信息部分(Informational),成功(Success),轉發(Redirection),客戶端錯誤(Client-Error),服務端錯誤(Server-Error),全局錯誤(Global-Failure)幾個部分。這個表格有如下格式:

類型(Type,就是Informational), Number, Default Reason Phrase [RFC3261]

如下信息需要提供給RFC出版機構來註冊新的應答碼或者方法:


o 應答碼和方法需要註冊的RFC號碼
o 應答碼號碼或者方法名
o 缺省應答碼的原因說明

27.5 “message/sip” MIME類型
本文檔註冊了”message/sip”MIME媒體類型,目的是允許SIP可以通過SIP包體隧道,首要用於端到端的安全保障。這個媒體類型由如下部分組成:

媒體類型名字:    message
媒體子類型:    sip
要求的參數:    none
可選的參數:    version/Encoding scheme/Security considerations
version: 這個打包的消息的SIP-version號碼(比如”2.0”)。如果沒有提供,version的缺省值就是”2.0”。
Encoding scheme: SIP消息包含一個8位的頭,在二進制的MIME數據對象後邊可選。同樣的,SIP消息必須把這個當作一個二進制值。在通常情況下,SIP消息通過二進制兼容的通訊協議傳送,不需要特別的編碼方式。
Security considerations: 本參數用於同23.4給出的S/MIME安全機制一致,請參見下邊的例子和說明。

27.6 新Content-Disposition 參數註冊
本文檔也註冊了4個新的Content-Disposition頭”disposition-types”: altert,icon,session和render。作者要求這些值在IANA中爲Content-Disposition登記。

對於”disposition-types”的描述,包括例子和說明,在20.11中說明。

在IANA註冊中的簡單描述是:

alter            包體是一個客戶定義的鈴聲用於提醒用戶。
icon            包體是一個顯示給用戶的icon
render        包體應當顯示給用戶
session        包體描述了一個通訊會話,例如RFC2327 SDP包體

28 同RFC 2543的改變
這個RFC修訂了RFC 2543。它主要和RFC2543向後兼容。這裏描述的變更主要修訂了RFC2543中發現的錯誤,並且提供了在RFC2543中沒有提及的相關情節信息。在本文中,協議以更清晰的層次結構描述。

我們把和RFC2543的永久改變,分成按功能行爲劃分這些區別。比如在互操作上不兼容,或者修正了某些情況下的錯誤操作,以及和RFC2543功能行爲不同但是不是一個潛在的兼容性問題。以及有數不清楚的澄清,在本文中沒有提及。

28.1 主要的功能改變
o 在UAC還沒有給出應答之前,UAC希望終止一個會話,它發送CANCEL來終止。如果原始INVITE依舊給出2xx應答,那麼UAC接着發送BYE。BYE只能發給現存的呼叫對話(leg)中(在這個RFC中成爲對話(dialog)),但是在RFC2543中可以在任何時間發送BYE。
o SIP的BNF改成RFC2234兼容的了。
o SIP URL的BNF更改的更加通用,在user部分,允許一個很大的字符集。此外,比較規則也簡化爲首先大小寫不敏感,接着詳細比較各個參數。最主要的變化是帶參數的URI和不帶這個參數(但是缺省值相等)的URI 判定是不相等的。
o 刪除了隱藏的Via。這要求發出絕對的信任,由於它依賴於下一個節點來執行這個不明確的操作。作爲替代,Via隱藏可以通過在proxy服務器上的本地實現選擇完成,於是在這裏不在說明。
o 在RFC2543,CANCEL和INVITE請求是混和的。他們現在分開了。當用戶發出一個INVITE請求接着CANCEL掉,INVITE事務將正常終結。UAS應當對原始INVITE請求給出一個487應答。
o類似的,CANCEL和BYE事務也是混和的;RFC2543允許UAS在收到BYE的時候,不給INVTE請求發送應答。本文檔不允許這種情況出現。原始的INVITE請求需要一個應答。
o 在RFC2543中,UA需要支持只有UDP的情況。在這個RFC中,UA應當支持UDP和TCP。
o 在RFC2543中,forking 分支proxy在收到多個拒絕應答的時候,只向下行元素髮出一個拒絕身份認證應答,在這個RFC中,proxy應當蒐集所有的拒絕並且把他們放在應答中發送。
o 在Digest信任書中,URI需要被引號引起來;這個在RFC2617和RFC2069是不一致的。
o SDP處理被分爲獨立的規範[13],並且更全面的描述了正式的通過SIP包體隧道進行的offer/answer交換過程。作爲SIP實現基線,SIP允許在INVITE/200或者200/ACK中存在;RFC2543間接指出了在INVITE,200和ACK中的單個事務使用這個方法,但是這個在RFC2543中沒有很好的定義。在SIP擴展中允許使用更復雜的SDP。
o 增加了對URI中和在Via頭域中的IPV6的全面支持。Via頭域允許方括號和冒號的參數,要求對Via頭域的IPV6的支持。這些字符在先前是不允許的。在理論上,這顆一導致和舊規範實現上的相互操作的問題。不過,我們觀察到大部分實現在這個參數上,接受非控制ASCII字符。
o DNS SRV處理步驟現在使用了單獨的規範[4]。這個步驟使用了SRV和NAPTR資源記錄,並且不在合併從SRV記錄的數據(RFC2543)。
o 循環檢測變成可選的了,替代爲強制使用Max-Forwards參數。這個循環檢測在RFC2543由嚴重bug,可能會在正常情況下把”螺旋”報告成爲一個錯誤。在這裏,可選的循環檢測步驟是更加全面的和正確的。
o 由於他們現在在對話中是作爲識別對話的基本要素存在,所以,對tag的使用是強制的(他們在RFC2543中是可選的)。
o 增加了Supported頭域,允許客戶端向服務器表示它支持什麼樣的擴展,服務器可以根據這個字段決定給出包含什麼樣擴展的應答,並且把他們需要的擴展支持放在Require字段裏邊。
o 幾個頭域的擴展參數的BNF描述在RFC2543中忽略了,這裏增加了。
o 處理Route和Record-Route的構在在RFC2543中是很不規範的,並且也不正確。它在本規範中更改成爲規範正確的(並且大大簡化了)。這是很大的改變。對於沒有使用”預先加載路由的”部屬情況下(在預先加載路由的時候,初始的請求有一個Route路由集合,這個集合不是由Record-Route構造的),依舊提供了向後兼容性。在預先加載路由的情況下,新舊機制是不能互相操作的。
o 在RFC2543中,消息中的行是可以由CR/LF/或者CRLF終端的。本規範只允許CRLF。
o 在CANCLE和ACK請求中的Route的使用,在RFC2543中沒有精確定義,在本文檔中定義了;如果請求有一個Route頭域,他的爲一個給請求的非2xx應答的CANCEL或者ACK應當包含相同的Route頭域。爲2xx應答的ACK請求使用2xx應答的Record-Route構造Route頭域值。
o RFC 2543允許一個UDP包中多個請求。這個使用方法在本文檔中刪去了。
o 對於Expires頭域和參數中的絕對時間的使用方式被刪去了。當各個節點之間時間不同步的時候,他會帶來戶操作的問題。本文檔使用相對時間。
o Via頭域中的branch參數現在是強制每一個元素都使用。它現在作爲事務的唯一標誌。這避免了RFC2543容易出錯的事務鑑別規則的複雜性。我們在這個參數值使用一個亂數cookie來檢查上一個節點產生的這個參數是否全局唯一的,如果不是,那麼舊採用舊的比較規則。因此,保證了互操作性。
o 在RFC2543,對TCP連接的關閉和CANCEL是相同的。當TCP連接在兩個proxy之間的時候,這在實現上是幾乎不可能的(也是錯誤的)。這個要求在這裏被刪去了,所以,TCP連接狀態和SIP處理之間沒有直接關係。
o RFC2543中,當UA到一個節點可以初始化一個新的事務,當對方正在進行事務處理的時候。在這裏被精確定義了。只允許初始化非INVITE請求,不允許INVITE請求。
o PGP被刪去了。它沒有很充分的定義,並且和更復雜的PGP MIME不兼容。替換成爲S/MIME。
o 增加了”sips” URI方案用於端到端的TLS通訊。這個方案是和RFC2543不能年個兼容的。現有的節點如果接收到請求的Request-URI中包含SIPS URI方案,將拒絕這個請求。這實際上是一個特性;它保證了對SIPS URI只會在所有節點都是安全的情況下被傳送。
o 在TLS上附加了安全特性,並且這裏也更廣泛更完整的描述了安全考慮。
o 在RFC 2543中,並不要求proxy轉發101到199的臨時應答到上行隊列。這裏被更改成爲必須轉發。這是非常重要的,因爲很多後續的特性都依賴於傳送所有的101到199的臨時應答。
o RFC 2543提及了很少的503應答。它用於標誌proxy失敗或者過載的情況。這要求某些特別的處理。尤其是,接收到503的接受方應當觸發一個對於下一個節點在DNS SRV的重新查找。同樣的,503應答只由proxy服務器在特定情況下轉發到上行隊列。
o RFC2543定義了,但是沒有充分指出,對於UA認證一個服務器的機制。這個已經刪去了。作爲替代,允許使用RFC2617的雙向認證步驟。
o 對於UA來說,除非它收到了初始請求的ACK,不能發送BYE到一個呼叫。這個在RFC2543是允許的,但是可能導致潛在的空轉可能。
o UA或者proxy不能發送CANCEL到一個事務,直到它得到了一個臨時應答。這個在RFC2543中是允許的,但是可能導致空轉的可能。
o 在註冊中的action參數被禁止使用了。它不足以提供任何有用的服務,並且會導致在proxy上的應用程序處理上的衝突。
o RFC2543對於multicast有一堆特別的情況。例如某個應答被禁止了,定時器調整了,等等。multicast現在受到更多限制,並且同unicast相反,協議操作不影響對multicast的使用。
o 基本的認證整個被刪除了,不允許用基本的認證。
o proxy不再立刻收到就轉發6xx應答。他們立刻CANCEL相關等待的分支。這也避免了潛在的空轉,使得UAC再2xx之後收到一個6xx。在除了這個空轉的情況,結果都必須是相同的-6xx轉發到上行隊列。
o RFC2543並不對請求的合併認爲是一個錯誤。這就導致在proxy上分支的請求稍後會在一個節點合併。只有在UA上能進行合併操作,並且處理步驟定義的是除了第一個請求都統統拒絕。

28.2 小功能性的變更
o 爲給用戶展示可選的內容,增加了Alert-Info,Error-Info,Call-Info頭域。
o 增加了Content-Language,Content-Disposition和MIME-Verison頭域。
o 增加了一個”glare hanling”機制來處理雙方同時都向對方提出一個re-INVITE。它使用信的491(Request Pending)錯誤碼。
o 增加了 In-Reply_To和Reply-To頭域來支持稍後對未接呼叫/消息的返回。
o 在SIP通訊協議中增加了TLS和SCTP。
o 描寫了很多機制來處理呼叫中的發生的錯誤;現在做了統一的處理。BYE用來發送會話終結。
o RFC2543要求INVITE應答通過TCP重新傳送,但是注意到實際上只對2xx應答是需要的。這就導致了人爲的協議不足。通過定義了一個一致的事務層,這就不在需要了。只有給INVITE的2xx應答需要基於TCP重傳。
o 客戶端和服務端事務機器現在基於超時機制,而不是基於重傳次數。這允許狀態機能夠更好的適應TCP和UDP。
o Date頭域在REGISTER應答中使用,提供一個簡單的自動配置UA的日期的機制。
o 允許註冊服務器拒絕過小的超時時間的註冊。並且爲此定義了423應答碼和Min-Expires頭域。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章