俗話說:山不轉路轉,只要我們有辦法建立任何一條連線到轉送連線的中繼伺服器,那內部網路就絕對不可能徹底限制住特定的連線。這是因為,任何原先被擋的連線,可以架構在沒被檔的連線上,間接forward到Internet。既然SSH被檔了,那把SSH架構在一條通行無阻的連線上不就皆大歡喜了XD。
可是,前面才說內部網路只允許HTTP和HTTPS通訊協定透過HTTP proxy連到外界,難不能我們要用超能力看網頁看出一條SSH連線?
當然不是這樣子啦!雖然網路環境可以設定成只允許HTTP和HTTPS連線藉由HTTP proxy連到外界,其他的一律擋掉,但是實際上,這個看似完美的機制中卻存在著一個很大的漏洞,那就是HTTPS。
當初HTTPS的立意就是為了要建立加密連線,讓不可見人的資訊不會遭人側錄。例如使用網路銀行(不用插ATM卡的那種),個人的財產資料是絕對不可以外洩的,因此HTTPS連線的資料傳輸全程使用SSL加密。就算HTTP proxy有cache網頁和修改網頁的機能,HTTPS的加密設計令HTTP proxy不可能記住HTTPS的資料傳輸,甚至是修改傳輸中的資料,所以HTTP proxy應對HTTPS連線請求的方法,就是不過問HTTPS的資料傳輸內容,直接原封不動的把HTTPS資料流轉送到目的地。
為了讓HTTP proxy能夠支援HTTPS通訊協定,HTTP proxy通常會提供connect這個指令,讓瀏覽器可以運用connect指令告知HTTP proxy,原封不動的轉送不可見光的資料流。就如前面所說的,HTTP proxy不會過問HTTPS資料流的內容,只要HTTP proxy知道這個連線請求是連到遠端伺服器的port 443,HTTP proxy就一定會允許HTTPS連線通過,那麼我們只要用connect指令告知HTTP proxy開啟間接連線,到SSH daemon有接聽port 443的伺服器,再讓SSH client利用這條連線和遠端的SSH daemon溝通,不就能成功建立SSH tunnel了嗎?
不幸的是,SSH client本身到現在還是不支援proxy server阿(不支援proxy server阿...不支援proxy server阿...不支援proxy server阿......)
難道就這樣玩完了嗎!?當然不是!
泛UNIX系統內建的OpenSSH client事實上是支援ProxyCommand這個機能的,這個機能讓SSH client不再過問本來得自行開啟與維護的TCP連線,把連線任務完全轉交給ProxyCommand指定的程式工具,然後SSH client再利用作業系統強大的pipe機能,把SSH資料流與程式工具的stdin和stdout接起來,讓程式工具把SSH client透過stdin丟進來的SSH資料流轉送給TCP連線,同時把TCP連線傳進來的SSH資料流透過stdout丟回SSH client,只要這個程式工具能夠運用HTTP proxy的connect指令建立間接連線,不就可以讓SSH資料流通過HTTP proxy到目的地了嗎!
話雖如此,ProxyCommand這機能不是所有的SSH client都有支援。OpenSSH這個強勢到幾乎是業界標準的套件,其client程式早就有提供ProxyCommand機能,但是在Windows方面,Putty的Windows版則是到2007年出的0.59版才有ProxyCommand機能。若要使用ProxyCommand時,得注意一下自己的SSH client有沒有支援。
確定自己的SSH client有ProxyCommand機能之後,接下來就是要找個能把stdin stdout的資料流和TCP連線接起來的程式工具。如果內部網路的HTTP proxy不需要指定帳號密碼就能使用,而且自己的作業系統有內建或是安裝netcat的OpenBSD/FreeBSD特化版(也就是有支援"-X"和"-x"這兩個參數),那恭喜你,這個特化的netcat正是我們需要的一把瑞士刀。如此一來,OpenSSH client的使用者,只要把以下文字內容用文字編輯器加進"/home/myusername/.ssh/config"這個檔案內就好了,若沒有這檔案,就自己建立一個:
Host host.com *.domain.org ProxyCommand nc -v -X connect -x proxy.mynetwork.com:3128 %h %p ServerAliveInterval 30這裡說明一下各參數的用途:
Host參數=從這個參數開始到下一個Host參數或檔案結尾之前的所有設定,會套用到SSH client每個連到指定SSH server的連線。在這個例子中,每次SSH client連到host.com或*.domain.org時,會套用Host參數之後的所有設定。
ProxyCommand=指定程式指令以執行我們需要的瑞士刀。在這個例子中,每次SSH client準備連到host.com或*.domain.org時,會讓netcat代理SSH client開啟和維護連線,而netcat則會根據SSH client丟過來的%h %p參數得知SSH client欲連到什麼位址和什麼port,先連到proxy.mynetwork.com:3128,再用connect指令告知HTTP proxy開啟間接連線到SSH server。
ServerAliveInterval=設定SSH client過多久沒有SSH資料流進出時,就透過SSH資料流發送訊息到SSH server,以確認連線是否異常。
如果系統的netcat不是OpenBSD特化版,或者是內部網路的HTTP proxy要求輸入帳號密碼才能使用(因為netcat本身不支援HTTP proxy的帳號密碼認証),那麼我們可以替換掉netcat,改用proxytunnel這個工具建立連線:
Host host.com *.domain.org ProxyCommand proxytunnel -v -p proxy.mynetwork.com:3128 -d %h:%p -H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Win32)\n" ServerAliveInterval 30這裡的ProxyCommand設定會讓SSH client以proxytunnel這工具代為開啟和維護連線,而proxytunnel則會根據SSH client丟過來的%h %p參數得知SSH client欲連到什麼位址和什麼port,先連到proxy.mynetwork.com:3128,再用connect指令告知HTTP proxy開啟間接連線到SSH server。另外,proxytunnel可以偽裝平常瀏覽器連線到proxy時會傳送給proxy的header(在這個例子中是"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Win32)\n"這個字串),如果HTTP proxy太機車,會根據header內容選擇性擋掉連線請求的話,可以設定header字串矇混過關XD。至於proxy的帳號密碼認証方面,因為proxytunnel本身就支援HTTP proxy的帳號密碼認証,所以可以輕鬆應付需要輸入帳號密碼才能使用的HTTP proxy,只要在proxytunnel的參數中加上"-u username -s password"就可以了。
若自己接觸到的系統環境不只其中一種,也可以把這檔案直接copy下來,再依據自己使用中的系統和網路環境,自行更改註解掉的指令參數:
Host host.com *.domain.org # select proxytunnel (plus header "User-Agent") or netcat-openbsd to make ssh over proxy ProxyCommand proxytunnel -v -p proxy.mynetwork.com:3128 -d %h:%p #-H "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Win32)\n" #ProxyCommand nc -v -X connect -x proxy.mynetwork.com:3128 %h %p ServerAliveInterval 30
不同的SSH client,config的方式也會有所不同。以上是OpenSSH client的設定方法,若使用的是Putty還是其他SSH client,請自己參考程式說明手冊設定。
沒有留言:
張貼留言