我昨天在授課的時候,突然遇到 Chrome 瀏覽器無法瀏覽網站的情況(ERR_UNSAFE_PORT
),我踩到一個不知道算不算罕見的地雷,在深入瞭解之後,覺得有必要寫成文章提醒大家,因為你還真的很有可能會在不久的將來遇到這個問題,看完文章才不會讓你日後鬼打牆太久,讓我們繼續看下去。
問題發生的過程
我昨天在示範如何將 ASP.NET Core 部署到 IIS 站台,我很隨意的挑選了一個吉利的數字 10080
當成網站的 HTTP 埠號,結果用 Google Chrome 開啟網頁後,竟然出現以下錯誤:
由於之前並沒有遇到過這種狀況,什麼叫 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 的瀏覽器都連不上,直接從用戶端就封鎖了連線,完全連不上! 🔥
若要讓 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 的網站,會出現以下畫面:
我從網路上只能找到一份相當古老的歷史文件 (April 21, 2008),基本上沒有什麼公信力,文件所列的 Ports 清單也跟 Chromium 不太一樣。
我最後則是從 Firefox 的原始碼找到一份測試案例,裡面有提到 WHATWG community 的 Fetch 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%
) 會選到 5060
與 5061
這兩個黑名單的埠號,請大家務必小心!
我有看了 ASP.NET Core 6.0 原始碼,他們並沒有對這兩個 Ports 做排除,我想應該「很少人這麼好運」會選中這兩個 Ports,但中獎率確實比中樂透還高阿! 😅
後記
我們軟體開發這一行,有太多的鬼故事,我們常常會遇到無法解釋的問題,我們都知道解決問題的方法很簡單,你可能會想:「就換個 Port 就好啦,幹嘛這麼麻煩?」但我認為,每一次的鬼打牆就是最好的學習機會,找尋每一個幽靈背後的科學原理,才是持續進步的不二法門!
相關連結