連接埠敲門
與 fwknop 相容的單封包授權(SPA,Single Packet Authorization):受保護的連接埠平時無法從外部連線,用戶端先傳送一個加密、帶 HMAC 認證且防重放的敲門封包,Gately 認證通過後,只為這個來源位址在限定時間內放行。常用於保護 SSH 直連:Web 終端機用不了的情境(scp、IDE 遠端開發、連接埠轉發)也能安全地從外網連線,掃描器與暴力破解看不到連接埠。
功能
- 相容 fwknop 用戶端:直接使用 fwknop 官方用戶端(Linux、macOS、WSL),金鑰格式與
fwknop -k產生的KEY_BASE64、HMAC_KEY_BASE64相同,規則頁可一鍵產生用戶端命令與~/.fwknoprc設定段; - 安全:封包以 AES-256-CBC 加密,先驗證 HMAC(SHA-256 / 384 / 512)再解密,金鑰不符的封包不會進入解密流程;每個封包只能使用一次(防重放),時間戳超出有效期(預設 120 秒)即拒絕;可限定使用者名稱、可要求封包寫明放行位址;
- 防火牆攔截:受保護連接埠寫入系統防火牆(nftables,核心沒有 nf_tables 時使用 iptables + ipset),只放行敲門成功的位址,保護本機 sshd 等不經過 Gately 的服務;
- Gately 入口依敲門放行:連接埠轉發、協定分流、STUN 內建轉發的規則,以及協定分流中的單條路由,可以選擇「需要敲門」,由 Gately 自己判斷,不需要防火牆權限,Windows、macOS、沒有
NET_ADMIN的容器也能使用; - 只開一個連接埠:協定分流可以識別經 TCP 送來的敲門封包(
fwknop -P tcp),同一個連接埠既接收敲門,又依敲門結果放行 SSH 等路由; - 與入侵防護聯動:被拒絕的敲門會發布「連接埠敲門被拒絕」事件,入侵防護內建「連接埠敲門失敗」範本可依次數封鎖來源;已被封鎖的位址送來的敲門直接丟棄;
- 目前授權一覽(剩餘時間、可撤銷),敲門成功與被拒絕都記錄在執行日誌,可在通知中心訂閱。
快速開始:保護本機 SSH
- 開啟「連接埠敲門」,新增規則:連接埠填
tcp/22,開啟「防火牆攔截」,金鑰留空會自動產生; - 在規則卡片上點「用戶端」,填寫伺服器的網域或公網 IP,複製命令列或
~/.fwknoprc設定段; - 在用戶端安裝 fwknop:macOS
brew install fwknop,Debian / Ubuntuapt install fwknop-client,Windows 在 WSL 中安裝; - 敲門後 30 秒內連線 SSH:
fwknop -n gately-ssh && ssh user@example.com敲門封包預設送到 UDP 62201 連接埠。Gately 部署在路由器後面時,需要把 UDP 62201 與受保護連接埠一起轉發到 Gately 所在的主機;開啟「自動放行防火牆」後,本機防火牆(OpenWrt fw4、firewalld、ufw 等)會自動放行敲門連接埠,攔截生效後也放行受保護連接埠,能否連線只由敲門決定。
避免把自己鎖在外面
- 預設開啟「內網免敲門」:私有位址、連結本機位址與本機網卡所在的公網 IPv6 網段(網卡前綴為 /64 或更短時按該前綴,雲端主機常見的 /124、/128 只包含本機自身)無需敲門,可以在設定中追加免敲門白名單。電信級 NAT 位址 100.64.0.0/10 不在其中:同一電信業者的其他使用者也使用這段位址;Tailscale 使用者可以把 100.64.0.0/10 加到免敲門白名單;
- 開啟防火牆攔截時已建立的連線不受影響,授權到期後已建立的連線也照常保持;
- Gately 正常停止時會刪除攔截規則;被強制結束(
kill -9、docker rm -f)時規則會保留,直到 Gately 重新啟動。請確認能從內網或其他途徑登入這台機器。
規則
| 欄位 | 說明 |
|---|---|
| 連接埠 | 用戶端可以請求放行的連接埠,如 tcp/22、udp/51820,最多 16 個。用戶端 -A 參數中的連接埠必須全部在此清單中,否則整個敲門被拒絕 |
| 防火牆攔截 | 開啟後在系統防火牆中攔截這些連接埠,只放行敲門成功的位址;關閉時不更動防火牆,規則只供「需要敲門」的入口引用 |
| 加密金鑰 / HMAC 金鑰 | base64 編碼,留空自動產生(32 / 64 位元組,與 fwknop -k 相同),也可以填寫既有 fwknop 伺服器端的金鑰。複製規則會產生新金鑰;修改、停用或刪除規則會撤銷它產生的全部授權 |
| HMAC 演算法 | SHA-256(fwknop 預設)、SHA-384、SHA-512,需與用戶端的 --hmac-digest-type 一致 |
| 放行時長 | 敲門成功後可以建立新連線的時間,預設 30 秒 |
| 用戶端最長時長 | 用戶端以 -f 請求更長時長時的上限(預設 300 秒),0 表示忽略用戶端請求的時長;請求比放行時長短時一律採用 |
| 限定使用者名稱 | 只接受封包中使用者名稱為此值的敲門(fwknop 預設傳送本機登入名稱,可用 -U 指定) |
| 要求寫明位址 | 拒絕不帶位址的封包(fwknop -s),用戶端必須用 -R 或 -a 寫明放行位址 |
被連接埠轉發、協定分流或 STUN 引用的規則無法刪除,卡片上會列出引用方。
放行哪個位址
-R(建議):用戶端先查詢自己的公網 IPv4 寫入封包,封包即使在途中被攔截,也無法用於其他位址;-s:封包不帶位址,放行封包的來源位址。攔截封包的人有機會搶先從自己的位址重放,規則可開啟「要求寫明位址」拒絕這種封包;-a 位址:放行指定的位址,例如替另一台裝置敲門。
fwknop 2.6 用戶端只能經 IPv4 傳送敲門封包、放行 IPv4 位址,伺服器需要能經 IPv4 存取;Gately 本身也接受經 IPv6 傳來的敲門封包,放行其來源位址。
全域設定
- UDP 敲門連接埠:預設 62201(fwknop 用戶端的預設連接埠);填 0 不監聽 UDP,只接收經協定分流送來的敲門。沒有啟用的規則時不監聽;
- 自動放行防火牆:見上文;
- 內網免敲門 / 免敲門白名單:只影響防火牆攔截;「需要敲門」的入口由各自的 IP 名單控制;
- 封包有效期:封包時間戳與本機時間的最大偏差,預設 120 秒,用戶端與伺服器的時鐘都需要準確。
防火牆攔截
| 環境 | 防火牆攔截 | Gately 入口依敲門放行 |
|---|---|---|
Linux(root 或 CAP_NET_ADMIN,有 nftables) | 可用 | 可用 |
Docker(host 網路 + cap_add: NET_ADMIN) | 可用,規則寫入主機 | 可用 |
| 群暉 DSM 等沒有 nf_tables 的 Linux | 使用 iptables(legacy)+ ipset,官方 Docker 映像檔已內建 | 可用 |
| Windows、macOS、FreeBSD、沒有權限的 Linux | 無法使用,頁面頂部會給出原因 | 可用 |
Gately 在 nftables 中建立獨立的 inet gately_knock 表,不更動系統既有的規則:prerouting 鏈(優先順序 -160,連線追蹤之後、目的位址轉換之前)把送往受保護連接埠的封包交給 gate 鏈,依序放行目標不是本機的流量(經本機轉發給其他裝置的連線不受影響)、回環介面、已建立的連線、TCP 中不是發起連線的封包、免敲門網段與敲門放行集合中的 位址 + 協定 + 連接埠,其餘丟棄。在 prerouting 判斷,因此對應到 Docker 容器的連接埠依對應前的連接埠攔截。放行寫入帶逾時的集合元素,到期由核心自動刪除。
沒有 nf_tables 時改用 iptables 的 mangle 表:PREROUTING 跳到 GATELY_KNOCK,每個受保護連接埠一個 ipset 集合(gkn4_tcp_22 等,帶逾時)。表或跳轉被防火牆重新載入、nft flush ruleset 等清除後 10 秒內自動重寫,並帶上仍然有效的放行。頁面上的「檢視防火牆規則」顯示目前寫入的規則。
經連接埠轉發進來的 SSH
經 Gately 連接埠轉發到本機 127.0.0.1:22 的連線來自回環介面,不受防火牆攔截。這種情況請在連接埠轉發規則上選擇「需要敲門」,或在防火牆攔截中保護對外的轉發連接埠。
注意
- Docker 連接埠映射改寫來源位址:Gately 以橋接網路執行、敲門連接埠經
-p 62201:62201/udp映射時,若 Docker 的 userland-proxy 處理了這個映射(例如經 IPv6、回送位址存取或關閉了 iptables 整合),Gately 看到的封包來源是 Docker 閘道位址,-s封包放行的就是閘道位址,等於沒有放行真實用戶端,甚至可能放行經同一閘道轉發的所有連線。請讓 Gately 使用 host 網路(防火牆攔截本來也需要),或讓用戶端用-R/-a寫明放行位址,並開啟「要求寫明位址」; - 只攔截 SYN 的取捨:為了不切斷啟用前已建立、但還沒有被連線追蹤記錄的連線,TCP 只丟棄發起連線的 SYN 封包,不帶 SYN 的封包直接放行。理論上,開啟了 SYN cookie(
net.ipv4.tcp_syncookies)的系統在 SYN 佇列溢位時,會接受一個能猜中 cookie 的裸 ACK 而建立連線;cookie 是用核心金鑰與時間計算出的 32 位元初始序號,實際幾乎不可能猜中;對安全要求極高的場景可以關閉 SYN cookie(sysctl net.ipv4.tcp_syncookies=0)。
Gately 入口依敲門放行
連接埠轉發、協定分流與 STUN(內建轉發)的「IP 存取控制」中可以選擇一條敲門規則作為「需要敲門」:來源位址必須持有該規則未到期的授權才能建立新連線(UDP 在建立新工作階段時判斷:授權到期後 WireGuard 等既有工作階段照常轉發,與防火牆攔截保持已建立連線一致;白名單 / 黑名單仍逐封包判斷),其餘連線直接中斷;與白名單 / 黑名單同時設定時兩者都要滿足。敲門規則可以關閉「防火牆攔截」,只供這些入口使用。
協定分流還可以在單條路由上選擇「需要敲門」,例如 443 連接埠上 HTTPS 路由對所有人開放,SSH 路由只對敲門成功的位址開放。
只開放一個連接埠
在協定分流規則中新增一條「連接埠敲門」路由(協定 spa),用戶端以 TCP 把敲門封包送到同一個連接埠:
fwknop -A tcp/443 -P tcp -p 443 -R -D example.com --use-hmac \
--key-base64-rijndael <加密金鑰> --key-base64-hmac <HMAC 金鑰>
ssh -p 443 user@example.com- 敲門路由把封包交給連接埠敲門模組,不轉發、不回覆;
-A中的連接埠需要在敲門規則的連接埠清單中(例如tcp/443); - 整條規則要求敲門時,沒敲門的來源只能使用敲門路由,敲門後才能使用其他路由與預設目標;
- 只有規則中有敲門路由時才識別敲門封包,不影響其他規則的協定識別;
- 敲門規則的 UDP 連接埠可以設為 0,對外只開放協定分流的連接埠;
- 帶敲門路由的協定分流連接埠與 UDP 敲門連接埠不能出現在開啟防火牆攔截的規則中(儲存、啟用時檢查;攔截後敲門封包本身無法送達),產生防火牆規則時也會自動排除這些連接埠。
與入侵防護聯動
被拒絕的敲門會發布「連接埠敲門被拒絕」事件(欄位 via 為 udp 或 tcp),同一來源每 5 秒最多一次。UDP 封包的來源位址可以偽造,為了不讓攻擊者借入侵防護封鎖任意 IP,經 UDP 傳來、HMAC 認證失敗的封包只計數、不發布事件;通過 HMAC 認證(出自持有金鑰的用戶端)但被規則拒絕的(解密失敗、重放、過期、請求未授權連接埠、使用者名稱不符等)才發布。經協定分流 TCP 連接埠傳來的封包來源經過握手,無法偽造,HMAC 不符也會發布。在入侵防護中用「連接埠敲門失敗」範本建立規則(預設 10 分鐘內 5 次即封鎖 1 天),持續傳送偽造封包的來源會被封鎖,被封鎖位址的敲門直接丟棄。非敲門格式的資料(連接埠掃描、其他協定)只計數、不發布事件。
認證前先按來源網段限速(IPv4 每個 /24、IPv6 每個 /64 每秒最多 10 個封包),再受全域每秒 200 個的上限約束,超出的直接丟棄:偽造封包洪水不會占滿 CPU,單一來源的洪水也不會擠掉其他來源的正常敲門。HMAC 認證失敗的封包不逐條記錄日誌,每分鐘彙總為一條「N 個來源的 M 個無效敲門封包」。
限制
- 只支援 fwknop 的 Rijndael(AES)CBC 模式加 HMAC,不支援 GnuPG、舊版 IV 模式與不帶 HMAC 的封包;
- 不執行命令訊息(
fwknop -C),不支援 NAT 存取請求(-N); - 敲門授權儲存在記憶體中,Gately 重新啟動後需要重新敲門(已建立的連線不受影響)。防重放紀錄同樣只在記憶體中,因此時間戳早於本次啟動的封包在重啟後一律拒絕;用戶端時鐘比伺服器慢時,重啟後頭幾秒的敲門可能被拒絕,再敲一次即可。