使用SO_REUSEADDR和SO_EXCLUSIVEADDRUSE
開發安全的高階網路基礎結構是大部分網路應用程式開發人員的優先順序。 不過,即使考慮完全安全的解決方案時,通訊端安全性仍然相當重要,但經常會忽略。 具體而言,通訊端安全性會處理系結至先前由另一個應用程式進程系結的相同埠的程式。 在過去,網路應用程式可能會「攔截」另一個應用程式的埠,這可能會導致「阻斷服務」攻擊或資料竊取。
一般而言,通訊端安全性適用于伺服器端進程。 更具體來說,通訊端安全性適用于接受連線並接收 IP 資料包流量的任何網路應用程式。 這些應用程式通常會系結至已知的埠,而且是惡意網路程式碼的常見目標。
用戶端應用程式不太可能是這類攻擊的目標,不是因為它們較容易攻擊,但因為大部分用戶端系結至「暫時」本機埠,而不是靜態「服務」埠。 除非有吸引人的架構原因,否則用戶端應用程式應該一律在名稱參數所指向的SOCKADDR結構中指定埠 0,以 (系) 結至暫時埠。 暫時本機埠是由大於埠 49151 的埠所組成。 專用服務的大部分伺服器應用程式會系結至小於或等於埠 49151 的已知保留埠。 因此,對於大部分的應用程式而言,用戶端和伺服器應用程式之間的系結要求通常不會發生衝突。
本節說明各種 Microsoft Windows 平臺上的預設安全性層級,以及特定通訊端選項 如何SO_REUSEADDR 和 SO_EXCLUSIVEADDRUSE 影響網路應用程式安全性。 Windows Server 2003 和更新版本提供稱為增強式通訊端安全性的其他功能。 這些通訊端選項的可用性和增強的通訊端安全性會因 Microsoft 作業系統版本而異,如下表所示。
平台 | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | 增強的通訊端安全性 |
---|---|---|---|
Windows 95 | 可用 | 無法使用 | 無法使用 |
Windows 98 | 可用 | 無法使用 | 無法使用 |
Windows Me | 可用 | 無法使用 | 無法使用 |
Windows NT 4.0 | 可用 | Service Pack 4 和更新版本提供 | 無法使用 |
Windows 2000 | 可用 | 可用 | 無法使用 |
Windows XP | 可用 | 可用 | 無法使用 |
Windows Server 2003 | 可用 | 可用 | 可用 |
Windows Vista | 可用 | 可用 | 可用 |
Windows Server 2008 | 可用 | 可用 | 可用 |
Windows 7 和更新版本 | 可用 | 可用 | 可用 |
使用SO_REUSEADDR
SO_REUSEADDR通訊端選項可讓通訊端強制系結至另一個通訊端所使用的埠。 第二個通訊端會呼叫 setockopt ,並將 optname 參數設定為 SO_REUSEADDR ,而 optval 參數會設定為 TRUE 的布林值 ,然後再呼叫 與原始通訊端相同的埠系 結 。 第二個通訊端成功系結之後,系結至該埠的所有通訊端行為都不確定。 例如,如果相同埠上的所有通訊端都提供 TCP 服務,則透過埠的任何連入 TCP 連線要求都無法保證由正確的通訊端處理, 行為不具決定性。 惡意程式可以使用 SO_REUSEADDR 強制系結已用於標準網路通訊協定服務的通訊端,以拒絕對這些服務的存取。 不需要特殊許可權才能使用此選項。
如果用戶端應用程式在伺服器應用程式能夠系結至相同的埠之前系結至埠,則可能會造成問題。 如果伺服器應用程式使用 SO_REUSEADDR 通訊端選項強制系結至相同的埠,則系結至該埠的所有通訊端行為都不確定。
這個不具決定性行為的例外狀況是多播通訊端。 如果兩個通訊端系結至相同的介面和埠,而且是相同多播群組的成員,資料將會傳遞至這兩個通訊端,而不是任意選擇的通訊端。
使用 SO_EXCLUSIVEADDRUSE
在引進 SO_EXCLUSIVEADDRUSE 通訊端選項之前,網路應用程式開發人員可以執行一些動作,以防止惡意程式系結至網路應用程式本身的通訊端系結的埠。 為了解決此安全性問題,Windows Sockets 引進了 SO_EXCLUSIVEADDRUSE通訊端選項,可在 service Pack 4 (SP4) 和更新版本Windows NT 4.0 上使用。
SO_EXCLUSIVEADDRUSE通訊端選項只能由 Windows XP 和更早版本的 Administrators 安全性群組成員使用。 本文稍後將討論此需求在 Windows Server 2003 和更新版本上變更的原因。
設定SO_EXCLUSIVEADDRUSE選項的方式是呼叫setockopt函式,並將optname參數設定為SO_EXCLUSIVEADDRUSE,而optval參數會在通訊端系結之前設定為TRUE的布林值。 設定選項之後,後續系結呼叫的行為會根據每個系結呼叫中指定的網路位址而有所不同。
下表描述當第二個通訊端嘗試使用特定通訊端選項系結至先前由第一個通訊端系結至的位址時,Windows XP 和更早版本中發生的行為。
注意
在下表中,「萬用字元」 表示指定通訊協定的萬用字元位址 (,例如 IPv4 的 「0.0.0.0」 和 IPv6) 的 「::」。 「特定」表示指派介面的特定 IP 位址。 表格儲存格指出系結是否成功 (「成功」) ,或 針對 WSAEADDRINUSE 錯誤傳回 (「INUSE」錯誤; WSAEACCES 錯誤的 「ACCESS」) 。
第一個 系結 呼叫 | 第二個 系結 呼叫 | ||||||
預設 | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | |||||
萬用字元 | 特定 | 萬用字元 | 特定 | 萬用字元 | 特定 | ||
預設 | 萬用字元 | INUSE | INUSE | 成功 | 成功 | INUSE | INUSE |
特定 | INUSE | INUSE | 成功 | 成功 | INUSE | INUSE | |
SO_REUSEADDR | 萬用字元 | INUSE | INUSE | 成功 | 成功 | INUSE | INUSE |
特定 | INUSE | INUSE | 成功 | 成功 | INUSE | INUSE | |
SO_EXCLUSIVEADDRUSE | 萬用字元 | INUSE | INUSE | ACCESS | ACCESS | INUSE | INUSE |
特定 | INUSE | INUSE | ACCESS | ACCESS | INUSE | INUSE |
當兩個通訊端系結至相同的埠號碼,但在不同的明確介面上時,不會發生衝突。 例如,在電腦有兩個 IP 介面的情況下, 10.0.0.1 和 10.99.99.99,如果第一次系 結 的呼叫是在 10.0.0.1 上,且埠設定為 5150 且 SO_EXCLUSIVEADDRUSE 指定,則第二次呼叫會 系結 于 10.99.99.99.99,且埠也設定為 5150,且未指定任何選項成功。 不過,如果第一個通訊端系結至萬用字元位址和埠 5150,則任何後續系結呼叫埠 5150 並設定SO_EXCLUSIVEADDRUSE將會失敗,且系結作業所傳回的WSAEADDRINUSE或WSAEACCES。
如果第一次呼叫 系結 會設定 SO_REUSEADDR 或完全沒有通訊端選項,第二個 系結 呼叫將會「攔截」埠,而應用程式將無法判斷兩個通訊端收到傳送至「共用」埠的特定封包中的哪一個。
呼叫 系結 函式的一般應用程式不會配置系結通訊端供獨佔使用,除非在通訊端上呼叫 SO_EXCLUSIVEADDRUSE 通訊端選項,然後再呼叫 系結 函式。 如果用戶端應用程式系結至暫時埠或伺服器應用程式系結至相同埠之前的特定埠,則可能會造成問題。 在呼叫系結函式之前,伺服器應用程式可以使用通訊端上的SO_REUSEADDR通訊端選項強制系結至相同的埠,但系結至該埠的所有通訊端行為則不定。 如果伺服器應用程式嘗試使用 SO_EXCLUSIVEADDRUSE 通訊端選項來獨佔使用埠,要求將會失敗。
相反地,具有 SO_EXCLUSIVEADDRUSE 集的通訊端不一定會在通訊端關閉之後立即重複使用。 例如, 如果接聽 通訊端SO_EXCLUSIVEADDRUSE集合接受連線,然後關閉之後,另一個通訊端 (也會與 SO_EXCLUSIVEADDRUSE) 系結至與第一個通訊端相同的埠,直到原始連線變成非使用中為止。
此問題可能會變得複雜,因為基礎傳輸通訊協定可能不會終止連線,即使通訊端已關閉也一樣。 即使應用程式已關閉通訊端,系統也必須傳輸任何緩衝的資料、將正常中斷連線訊息傳送給對等,以及等候對等對應的正常中斷連線訊息。 基礎傳輸通訊協定可能永遠不會釋放連線;例如,參與原始連線的對等可能會公告零大小的視窗,或某種形式的「攻擊」組態。 在這種情況下,用戶端連線仍會處於作用中狀態,即使要求關閉它,因為未清除的資料會保留在緩衝區中。
若要避免這種情況,網路應用程式應該呼叫已設定SD_SEND旗標的 關機 ,然後等候 recv 迴圈,直到透過連線傳回零個位元組為止,確保正常關機。 這可保證所有資料都是由對等接收,並同樣地向對等確認其已接收所有傳輸的資料,以及避免上述埠重複使用問題。
SO_LINGER通訊端選項可能會在通訊端上設定,以防止埠轉換為「作用中」等候狀態;不過,不建議這樣做,因為它可能會導致不想要的效果,例如重設連線。 例如,如果資料是由對等所接收,但仍不受其攔截,而本機電腦會關閉通訊端並設定SO_LINGER,則會重設這兩部電腦之間的連線,以及對等捨棄的未清除資料。 挑選適合的延遲時間很困難,因為較小的逾時值通常會導致突然中止的連線,而較大的逾時值可讓系統容易遭受拒絕服務攻擊, (建立許多連線,並可能停止/封鎖應用程式執行緒) 。 關閉具有非零逾時值的通訊端,也可能會導致 closesocket 呼叫封鎖。
增強的通訊端安全性
Windows Server 2003 版本已新增增強的通訊端安全性。 在先前的 Microsoft 伺服器作業系統版本中,預設通訊端安全性可以輕鬆地允許進程從未建議的應用程式攔截埠。 在 Windows Server 2003 中,通訊端預設不是可共用狀態。 因此,如果應用程式想要允許其他進程重複使用已系結通訊端的埠,則必須特別啟用它。 如果是這種情況,在埠上呼叫 系結 的第一個通訊端必須在通訊端上設定 SO_REUSEADDR 。 當第二個 系結 呼叫是由對系 結進行原始呼叫的相同使用者帳戶執行時,就會發生此案例的唯一例外狀況。 此例外狀況只存在以提供回溯相容性。
下表描述當第二個通訊端嘗試使用特定通訊端選項系結至先前系結至第一個通訊端所系結的位址時,Windows Server 2003 和更新版本的作業系統中所發生的行為。
注意
在下表中,「萬用字元」 表示指定通訊協定的萬用字元位址 (,例如 IPv4 的 「0.0.0.0」 和 IPv6) 的 「::」。 「特定」表示指派介面的特定 IP 位址。 表格儲存格指出系結是否成功 (「成功」) ,或 針對 WSAEADDRINUSE 錯誤傳回 (「INUSE」的錯誤; WSAEACCES 錯誤的 「ACCESS」) 。
另請注意,在此特定資料表中,兩個 系結 呼叫都是在相同的使用者帳戶下進行。
第一個 系結 呼叫 | 第二個 系結 呼叫 | ||||||
預設 | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | |||||
萬用字元 | 特定 | 萬用字元 | 特定 | 萬用字元 | 特定 | ||
預設 | 萬用字元 | INUSE | Success | ACCESS | Success | INUSE | Success |
特定 | Success | INUSE | Success | ACCESS | INUSE | INUSE | |
SO_REUSEADDR | 萬用字元 | INUSE | 成功 | 成功 | 成功 | INUSE | Success |
特定 | Success | INUSE | 成功 | 成功 | INUSE | INUSE | |
SO_EXCLUSIVEADDRUSE | 萬用字元 | INUSE | ACCESS | ACCESS | ACCESS | INUSE | ACCESS |
特定 | Success | INUSE | Success | ACCESS | INUSE | INUSE |
上述表格中的一些專案值得說明。
例如,如果第一個呼叫端在特定位址上設定 SO_EXCLUSIVEADDRUSE ,而第二個呼叫端嘗試呼叫系 結 與相同埠上的萬用字元位址,則第二個 系結 呼叫將會成功。 在此情況下,第二個呼叫端會系結至所有介面,但第一個呼叫端所系結的特定位址除外。 請注意,此案例的反向不是 true:如果第一個呼叫端設定 SO_EXCLUSIVEADDRUSE ,且呼叫會與萬用字元旗標系 結 ,則第二個呼叫端無法呼叫系 結 與相同的埠。
當通訊端系結呼叫在不同的使用者帳戶下進行時,通訊端系結行為會變更。 下表指定當第二個通訊端嘗試系結至先前由第一個通訊端系結的位址時,Windows Server 2003 和更新版本的作業系統使用特定通訊端選項和不同的使用者帳戶系結至位址時,就會發生的行為。
第一個 系結 呼叫 | 第二個 系結 呼叫 | ||||||
預設 | SO_REUSEADDR | SO_EXCLUSIVEADDRUSE | |||||
萬用字元 | 特定 | 萬用字元 | 特定 | 萬用字元 | 特定 | ||
預設 | 萬用字元 | INUSE | ACCESS | ACCESS | ACCESS | INUSE | ACCESS |
特定 | Success | INUSE | Success | ACCESS | INUSE | INUSE | |
SO_REUSEADDR | 萬用字元 | INUSE | ACCESS | 成功 | 成功 | INUSE | ACCESS |
特定 | Success | INUSE | 成功 | 成功 | INUSE | INUSE | |
SO_EXCLUSIVEADDRUSE | 萬用字元 | INUSE | ACCESS | ACCESS | ACCESS | INUSE | ACCESS |
特定 | Success | INUSE | Success | ACCESS | INUSE | INUSE |
請注意,當 系結 呼叫在不同的使用者帳戶下進行時,預設行為會不同。 如果第一個呼叫端未在通訊端上設定任何選項並系結至萬用字元位址,則第二個呼叫端無法設定 SO_REUSEADDR 選項,並成功系結至相同的埠。 未設定任何選項的預設行為也會傳回錯誤。
在 Windows Vista 和更新版本上,可以建立可透過 IPv6 和 IPv4 運作的雙堆疊通訊端。 當雙重堆疊通訊端系結至萬用字元位址時,指定的埠會保留于 IPv4 和 IPv6 網路堆疊上,以及與 SO_REUSEADDR 相關聯的檢查,並在設定) 時 ( SO_EXCLUSIVEADDRUSE。 這兩個網路堆疊上的檢查都必須成功。 例如,如果雙堆疊 TCP 通訊端設定 SO_EXCLUSIVEADDRUSE ,然後嘗試系結至埠 5000,則先前無法系結至埠 5000 (萬用字元或特定) 。 在此情況下,如果 IPv4 TCP 通訊端先前已系結至埠 5000 上的回送位址,則雙重堆疊通訊端的 系結 呼叫將會失敗,並出現 WSAEACCES。
應用程式策略
開發在通訊端層運作的網路應用程式時,請務必考慮所需的通訊端安全性類型。 用戶端應用程式 — 連接或傳送資料至服務的應用程式很少需要任何其他步驟,因為它們會系結至隨機本機 (暫時) 埠。 如果用戶端確實需要特定的本機埠系結才能正常運作,則必須考慮通訊端安全性。
除了多播通訊端之外 ,SO_REUSEADDR 選項在一般應用程式中很少使用,其中資料會傳遞到相同埠上系結的所有通訊端。 否則,任何設定此通訊端選項的應用程式都應該重新設計以移除相依性,因為它很容易遭受「通訊端攔截」攻擊。 只要 SO_REUSEADDR 通訊端選項可用來潛在攔截伺服器應用程式中的埠,就必須將應用程式視為不安全。
所有伺服器應用程式都必須針對強式通訊端安全性層級 設定SO_EXCLUSIVEADDRUSE 。 它不僅會防止惡意軟體攔截埠,也會指出另一個應用程式是否系結至要求的埠。 例如,如果另一個進程目前系結至特定介面上的相同埠,則具有SO_EXCLUSIVEADDRUSE通訊端選項組的進程在萬用字元位址上系結的呼叫將會失敗。
最後,即使 Windows Server 2003 中已改善通訊端安全性,應用程式應該一律設定 SO_EXCLUSIVEADDRUSE 通訊端選項,以確保它系結至進程所要求的所有特定介面。 Windows Server 2003 中的通訊端安全性會增加繼承應用程式的安全性層級,但應用程式開發人員仍必須設計其產品,並考慮安全性的所有層面。