2016年8月21日 星期日

鑿一個反向 ssh 隧道, 對朋友或世界展示筆電或家裡的某個服務

圖解正向及反向 ssh tunneling [2017/3/6 如果遇到 「Cannot assign requested address」 的錯誤, 可能需要在 ssh 命令列上加上 -4 的選項。 詳見 這篇]

你在自己的筆電或家裡的電腦上面安裝了一個神奇的服務, 心裡想著: 「不能只有我看到! 一定要展示給朋友、 甚至要展示給世界看!」 但是你沒有固定的 IP, 或是你的機器被防火牆保護住了, 朋友跟世界都看不見你有多帥。 這個時候, 如果你有一個 ssh 帳號, 而且那個帳號至少被允許使用一個空的 port, 那麼就可以透過反向 ssh 隧道 (reverse ssh tunnel) 對外展示你的服務了。

要學反向 ssh tunneling, 不如同時把正向 ssh tunneling 也一併弄懂。 找到 這一篇, 插圖把兩者合併畫在一起, 超讚超清楚。

以下假設你已玩過 坐 ssh 火車過山洞 那篇的 http over sshvnc over ssh, 對 ssh tunneling 已經略懂略懂。 我用更有 fu 的方式白話重畫如上圖。 圖中我們真正有興趣的是紫色的服務 (例如資料庫、 網頁、 串流音樂、 監視錄影影像、 ...): 客戶向伺服器提出請求 (箭頭方向), 伺服器提供資訊給客戶端 (貨車方向)。 至於綠色的 ssh 服務則是一條 "隧道", 用來幫紫色服務多開一個窗口 -- 把它拉到防火牆外面 -- 讓 "更多人" (小紫箭頭) 可以使用紫色的服務。 (原來的窗口當然還是可以繼續使用。)

如果紫色服務跟著 ssh 服務一起放在一部 具有公開 IP 的公司伺服器上面, 但紫色服務被防火牆保護住, 只允許少數人使用 (例如本公司辦公室內的員工), 而你卻需要從家裡/路上/旅館使用它, 那麼這時你就需要(從筆電上面)建立正向的 ssh 隧道。 語法類似這樣: ssh -fNL 特權入口:localhost:閒人勿近的管制入口 ckhung@penguin.tw 這彷彿是在 「筆記電腦:特權入口」 多開一個匝道接到原來的 「penguin.tw:閒人勿近的管制入口」。 例如 「坐 ssh 火車過山洞」 那篇裡面的 vnc 所鑽的, 就是正向的 ssh 隧道。

如果紫色服務位於你的筆電或你家電腦上, 而且你想把它展示給世界看, 但是它無法對外提供 ssh 服務 (例如因為它沒有公開的 IP, 或是因為 ISP 好心地用防火牆保護住它), 那麼這時你就需要(從筆電上面)建立反向的 ssh 隧道。 語法類似這樣: ssh -fNR 向朋友展示的櫥窗:localhost:只有我看到的服務 ckhung@penguin.tw 這彷彿是在 「penguin.tw:向朋友展示的櫥窗」 多開一個匝道接到原來的 「筆記電腦:只有我看到的服務」。 不僅如此, 還必須在 penguin.tw 幫朋友開一個 ssh 帳號, 這樣他才可以 (還有在 penguin.tw 上面有 ssh 帳號的任何人也都可以) 登入 penguin.tw, 下 (紫色服務的) 指令觀看 「localhost:向朋友展示的櫥窗」。

或者, 如果這個服務沒有隱私或機密的顧慮, 也可以不必幫朋友開帳號, 而是在 penguin.tw 的 /etc/ssh/sshd_config 裡面設定 GatewayPorts clientspecified 並且重新啟動 ssh 服務、 (在筆電,也就是 client 上面)改用這個指令鑿隧道: ssh -fNR '*:向朋友展示的櫥窗:localhost:只有我看到的服務' ckhung@penguin.tw (前面加 *: 並且外面加單引號或雙引號)。 如此一來, 全世界都能透過 penguin.tw 伺服器 「penguin.tw:向朋友展示的櫥窗」 觀看你的筆電表演。 詳見 這個問答

用一個具體的例子來練習反向 ssh tunneling。

  1. 在筆電上安裝 apache2 網頁伺服器。
  2. 在 /var/www/html/index.html 裡面打一些字。
  3. lynx http://localhost/ 指令確認伺服器架設成功。
  4. 在桌機 (假設 IP 是 192.168.34.56) 上安裝 openssh-server、 在 /etc/ssh/sshd_config 裡面加上 GatewayPorts clientspecified、 用 service ssh restart 重新啟動 ssh 服務。
  5. 在桌機上執行 lynx http://localhost:4380/ 當然會連線失敗。
  6. 在筆電上鑿反向 ssh 隧道: ssh -fNR 4380:localhost:80 192.168.34.56
  7. 在桌機上再次執行 lynx http://localhost:4380/ 看見筆電的網頁!
  8. 從筆電看 lynx http://192.168.34.56:4380/ 連線失敗。
  9. 在筆電上用 ps ax | grep 'ssh.*:.*:' 以及工人智慧 (肉眼) 找出先前鑿通的隧道並且用 kill 把它砍掉, 或是用這個指令直接砍掉 「本機上目前已鑿通的所有隧道」: kill $(ps ax | perl -ne 'print "$1\n" if (/(\d+).*\d\s+ssh.*:.*:/)')
  10. 重鑿一個 「對全世界開放」 的隧道: ssh -fNR *:4380:localhost:80 192.168.34.56
  11. 在筆電上再次執行 lynx http://192.168.34.56:4380/ 成功!

補充說明:

  1. 重要安全提醒: 實驗結束之後, 記得要砍掉所有的 ssh 隧道程序!
  2. 不論是正向或反向 ssh 隧道, 鑿隧道時, 當然要用 ssh 伺服器那頭的帳號密碼, 而不是本機 ssh 帳號密碼或紫色服務的帳號密碼。 兩者都用到的 -fN 選項意思是說 「我們只要鑿隧道, 不需要命令列; 請丟到背景執行」。
  3. 至於一般的翻牆上網 (例如 「坐 ssh 火車過山洞」 那篇當中, 透過 ssh 隧道上網 (http over ssh) 採用的是正向, 但更靈活彈性的 SOCKS proxy (ssh -fND ...)。 詳見 這個問答
  4. 不論是哪一種 ssh tunnel 都同時兼具翻牆及保護隱私的效果。 隧道全程加密, 所以隧道途中經過的地方, 就算有 NSA 或其他潰客在監聽, 也只會看到亂碼。 你只需要顧慮 「進隧道之前」 及 「出隧道之後」 的隱私威脅。 這也是為什麼有些時候明明 vnc 已經通了, 卻還要再包一層 ssh。 (vnc over ssh) 詳見 隱私攻防觀念
  5. 像我這種要看到命令列才有安全感的人, 出國玩的時候可能會想要用 ssh 連回家裡的電腦。 可是家裡的電腦沒有公開的 IP, 所以需要用反向 ssh 隧道把它拉到某部 (我所管轄的) 具有公開 IP 的伺服器上。 此時紫色的服務正好就是 ssh 本身, 所以只要鑿好反向 ssh 隧道, 一切就完工了。 詳見簡單明瞭的這一篇: 「Reverse SSH Tunnel 反向打洞實錄」
  6. 幫朋友或客戶鑿反向 ssh 隧道時, 請務必要負責任地向他解釋必要性跟風險, 也要請他在完工後記得提醒你要關閉隧道, 這樣才不會被誤會/被指責是暗中開後門。

這篇的解釋, 觀念上適用於資料庫、 網頁、 串流音樂、 監視錄影影像、 ... 等等任何網路服務。 至於實作上會遇到什麼問題? 請留言分享囉。

3 則留言:

  1. 「在 /etc/ssh/sshd_config 裡面加上 GatewayPorts clientspecified」的設定教學,很少有中文教學提到。

    感謝,很受用!

    回覆刪除
  2. 把一個簡單的觀念講的這麼複雜,看了非常累,不如參考這一編
    http://fred-zone.blogspot.tw/2010/08/reverse-ssh-tunnel.html

    回覆刪除