開發與部署網站時需注意不要使用到 ERR_UNSAFE_PORT 不安全的埠號 | The Will Will Web

The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

開發與部署網站時需注意不要使用到 ERR_UNSAFE_PORT 不安全的埠號

我昨天在授課的時候,突然遇到 Chrome 瀏覽器無法瀏覽網站的情況(ERR_UNSAFE_PORT),我踩到一個不知道算不算罕見的地雷,在深入瞭解之後,覺得有必要寫成文章提醒大家,因為你還真的很有可能會在不久的將來遇到這個問題,看完文章才不會讓你日後鬼打牆太久,讓我們繼續看下去。

問題發生的過程

我昨天在示範如何將 ASP.NET Core 部署到 IIS 站台,我很隨意的挑選了一個吉利的數字 10080 當成網站的 HTTP 埠號,結果用 Google Chrome 開啟網頁後,竟然出現以下錯誤:

ERR_UNSAFE_PORT

由於之前並沒有遇到過這種狀況,什麼叫 ERR_UNSAFE_PORT 呢?我當下先判斷可能跟 HSTS (HTTP Strict Transport Security) (HTTP強制安全傳輸技術) 有關,但調整了一下 Chrome 的 HSTS 設定,還是連不上。狀況很詭異,我甚至一度懷疑 Google Chrome 是不是把 HTTP (Port 80) 都給封鎖了?應該不太可能吧!結果我用 curl 呼叫這個網址,發現是可以連線的,只有 Google Chrome / Microsoft Edge 連不上而已。我最後換了一個 Port,並設定 HTTPS 安全連線,然後就可以運作了,真的相當詭異!

Google Chrome 有一組黑名單的埠號清單

我今天抽空研究了一下,發現在 Chromium 的原始碼中有定義一系列被列入黑名單的埠號清單 (blocked ports):

net/base/port_util.cc - chromium/src.git - Git at Google

// The general list of blocked ports. Will be blocked unless a specific
// protocol overrides it. (Ex: ftp can use port 21)
// When adding a port to the list, consider also adding it to kAllowablePorts,
// below.
const int kRestrictedPorts[] = {
    1,      // tcpmux
    7,      // echo
    9,      // discard
    11,     // systat
    13,     // daytime
    15,     // netstat
    17,     // qotd
    19,     // chargen
    20,     // ftp data
    21,     // ftp access
    22,     // ssh
    23,     // telnet
    25,     // smtp
    37,     // time
    42,     // name
    43,     // nicname
    53,     // domain
    69,     // tftp
    77,     // priv-rjs
    79,     // finger
    87,     // ttylink
    95,     // supdup
    101,    // hostriame
    102,    // iso-tsap
    103,    // gppitnp
    104,    // acr-nema
    109,    // pop2
    110,    // pop3
    111,    // sunrpc
    113,    // auth
    115,    // sftp
    117,    // uucp-path
    119,    // nntp
    123,    // NTP
    135,    // loc-srv /epmap
    137,    // netbios
    139,    // netbios
    143,    // imap2
    161,    // snmp
    179,    // BGP
    389,    // ldap
    427,    // SLP (Also used by Apple Filing Protocol)
    465,    // smtp+ssl
    512,    // print / exec
    513,    // login
    514,    // shell
    515,    // printer
    526,    // tempo
    530,    // courier
    531,    // chat
    532,    // netnews
    540,    // uucp
    548,    // AFP (Apple Filing Protocol)
    554,    // rtsp
    556,    // remotefs
    563,    // nntp+ssl
    587,    // smtp (rfc6409)
    601,    // syslog-conn (rfc3195)
    636,    // ldap+ssl
    989,    // ftps-data
    990,    // ftps
    993,    // ldap+ssl
    995,    // pop3+ssl
    1719,   // h323gatestat
    1720,   // h323hostcall
    1723,   // pptp
    2049,   // nfs
    3659,   // apple-sasl / PasswordServer
    4045,   // lockd
    5060,   // sip
    5061,   // sips
    6000,   // X11
    6566,   // sane-port
    6665,   // Alternate IRC [Apple addition]
    6666,   // Alternate IRC [Apple addition]
    6667,   // Standard IRC [Apple addition]
    6668,   // Alternate IRC [Apple addition]
    6669,   // Alternate IRC [Apple addition]
    6697,   // IRC + TLS
    10080,  // Amanda
};

由上述清單可以得知,我授課時所用到的 10080 正好就是黑名單之一! How Lucky!!! 😄

事實上,無論你走 HTTP 或 HTTPS,只要用到這幾個 Ports,就會讓所有 Chromium-based 的瀏覽器都連不上,直接從用戶端就封鎖了連線,完全連不上! 🔥

ERR_UNSAFE_PORT

若要讓 Google Chrome 可以開放這些限制的 Ports 清單,需要在啟動 Chrome 的時候加入 --explicitly-allowed-ports=10080 這樣的啟動參數。例如:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory=Default --explicitly-allowed-ports=10080

詳情請見 How to fix ERR_UNSAFE_PORT error on Chrome when browsing to unsafe ports 的各種回覆答案。

Mozilla Firefox 也有一組黑名單的埠號清單

沒錯,Mozilla Firefox 也有一組黑名單的埠號清單,我用 Firefox 開啟 Port 10080 的網站,會出現以下畫面:

This address is restricted

我從網路上只能找到一份相當古老的歷史文件 (April 21, 2008),基本上沒有什麼公信力,文件所列的 Ports 清單也跟 Chromium 不太一樣。

我最後則是從 Firefox 的原始碼找到一份測試案例,裡面有提到 WHATWG communityFetch Standard 規格中,有明確提到 2.9. Port blocking 清單! 🔥

Bingo! 我原本還以為不同瀏覽器可能會有不同的實作,有標準就好辦了,大家都可以清楚的知道哪些 Ports 絕對不能拿來用瀏覽器開啟了! 👍

如果你想要設定 Firefox 開放受限制的 Ports,可以參考 How to create a preference/string to override access to a restricted address/port. | Knowledge Base discussions | Forums | Mozilla Support 這份文件。(影片教學)

使用 .NET CLI 或 Visual Studio 2022 建立專案的注意事項

事實上,從 ASP.NET Core 6.0 開始,透過 .NET CLI 或 Visual Studio 2022 建立的全新專案,都會預設指派一個亂數的 Ports,我們可以從 Configure endpoints for the ASP.NET Core Kestrel web server 得知,新專案的 HTTP Ports 會介於 5000-5300 之間,而 HTTPS Ports 會介於 7000-7300 之間,而這個設定預設會放在 Properties/launchSettings.json 設定檔中。

是的,你沒想錯,你有 300 分之 2 的機率 (0.66%) 會選到 50605061 這兩個黑名單的埠號,請大家務必小心!

我有看了 ASP.NET Core 6.0 原始碼,他們並沒有對這兩個 Ports 做排除,我想應該「很少人這麼好運」會選中這兩個 Ports,但中獎率確實比中樂透還高阿! 😅

後記

我們軟體開發這一行,有太多的鬼故事,我們常常會遇到無法解釋的問題,我們都知道解決問題的方法很簡單,你可能會想:「就換個 Port 就好啦,幹嘛這麼麻煩?」但我認為,每一次的鬼打牆就是最好的學習機會,找尋每一個幽靈背後的科學原理,才是持續進步的不二法門!

相關連結